TypeScript & React Native: Using Pick<T, K> to avoid bloating my code
I have the following interface and React Native component that uses it:
import { KeyboardTypeOptions, TextInputProps } from 'react-native';
import { TextInput } from 'react-native-paper';
export interface ValidatedInputProps {
autoCapitalize?: 'none' | 'sentences' | 'words' | 'characters',
contentType: Pick<TextInputProps, 'textContentType'>,
isSecure?: boolean,
keyboard?: KeyboardTypeOptions,
label: string,
}
export const ValidatedInput = ({
autoCapitalize = 'none',
contentType,
isSecure = false,
keyboard = 'default',
label,
}: ValidatedInputProps) => {
return (
<TextInput
textContentType={contentType} <-- Error is flagged here
...other props
/>
);
};
This gives me the following error popup in VSCode:
Type 'Pick<TextInputIOSProps, "textContentType">' is not assignable to type '"none" | "name" | "URL" | "addressCity" | "addressCityAndState" | "addressState" | "countryName" | "creditCardNumber" | "emailAddress" | "familyName" | "fullStreetAddress" | ... 17 more ... | undefined'.
Type 'Pick<TextInputIOSProps, "textContentType">' is not assignable to type '"oneTimeCode"'.ts(2322)
index.d.ts(1250, 5): The expected type comes from property 'textContentType' which is declared here on type 'IntrinsicAttributes & Pick<TextInputProps, "textContentType" | "clearButtonMode" | "clearTextOnFocus" | "dataDetectorTypes" | "enablesReturnKeyAutomatically" | ... 114 more ... | "dense"> & { ...; } & { ...; }'
(JSX attribute) textContentType?: "none" | "name" | "URL" | "addressCity" | "addressCityAndState" | "addressState" | "countryName" | "creditCardNumber" | "emailAddress" | "familyName" | "fullStreetAddress" | ... 17 more ... | undefined
I'm obviously completely misunderstanding the point of the Pick<T, K>
type, but everything that I've read on the subject over the past two hours seems to imply that my usage is correct. So what am I missing?
I guess I could define my contentType
prop with the correct union (as I've done with autoCapitalize
), but who would want to bloat their code with that excessively-long string of characters, when it's already been defined elsewhere?! Can't I just import that property/type and be done with it??
Pick<Type, Keys>
Constructs an Object type by picking the set of property
Keys
(string literal or union of string literals) fromType
.
So it is not giving you the union of allowed values for textContentType
, but an Object type with a single key of textContentType
.
Instead you could extend a Picked version of TextInputProps
with the properties you need, then add your own properties to the interface.
import { KeyboardTypeOptions, TextInputProps } from 'react-native';
interface ValidatedInputProps extends Pick<TextInputProps, 'textContentType' | 'autoCapitalize'> {
isSecure?: boolean,
keyboard?: KeyboardTypeOptions,
label: string,
}
Alternatively you could just create local types by accessing each known property from the imported Object type.
import { KeyboardTypeOptions, TextInputProps } from 'react-native';
type myTextContentType = TextInputProps['textContentType']
type myAutoCapitalize = TextInputProps['autoCapitalize']
interface ValidatedInputProps {
textContentType?: myTextContentType,
autoCapitalize?: myAutoCapitalize,
isSecure?: boolean,
keyboard?: KeyboardTypeOptions,
label: string,
}