[英]Is there a way to infer the types of a specific value from an interface passed as a generic?
因为我是 TS 的新手,所以我完全有可能错误地处理了这个问题,但我想知道我是否有一些通用类型,我将通过它传递一个看起来像{[key: string]: string | boolean}
的接口。 {[key: string]: string | boolean}
是否可以知道 function 中使用该泛型的任何特定值的类型。
例如,我有一个类似的界面:
export interface Address {
addressId: string;
firstName: string;
lastName: string;
addressType: string;
addressLine1: string;
addressLine2: string;
city: string;
state: string;
country: string;
zipCode: string;
email1: string;
phone1: string;
primary: boolean;
nickName?: string;
}
我正在尝试做这样的事情:
function useForm<T>(initialValues: T) {
const [form, setForm] = useState<T>(initialValues);
const field = (key: keyof T) => {
const setValue = (newValue: T[keyof T]) => {
const newState = {
...form,
[key]: newValue
}
setForm(newState);
}
const value = form[key];
return {
value,
setValue
};
}
return {
form,
field,
};
}
我的 textField 有一个看起来像这样的界面
interface TextFieldProps {
field: {
setValue: (value: string) => void;
value: string;
};
label?: string;
placeholder?: string;
containerStyle?: ViewStyle;
}
在我的表格中看起来像
const {form, field} = useForm<Address>(someInitialAddress);
...
<TextField field={form("FirstName")} />
...
如果您尝试加载界面上不存在的字段,它已经引发类型错误,但我想确保您没有将基于 boolean 的值或其他内容加载到该字段中,我'当前收到此类型错误: Type '{ value: string | boolean | undefined; setValue: (newValue: string | boolean | undefined) => void; }' is not assignable to type '{ setValue: (value: string) => void; value: string; }'.
Type '{ value: string | boolean | undefined; setValue: (newValue: string | boolean | undefined) => void; }' is not assignable to type '{ setValue: (value: string) => void; value: string; }'.
任何帮助将不胜感激,谢谢!
所以也许 TypeScript 中还有更多开箱即用的东西,但似乎这个问题已经用现有的实用程序类型解决了。
根据这篇文章: https://medium.com/dailyjs/typescript-create-a-condition-based-subset-types-9d902cea5b8c
您可以为此定义一个类型,例如SubType<T, A>
,它将使用类型 T 的键子集构造一个新类型,这些键属于 A 类型。我很确定这就是您要寻找的。
子类型定义 - 这将never
将类型分配给不属于 A 类型的属性,因此它们将不允许使用并显示编译错误,在智能感知等中。
export type SubType<A, T> = Pick<A, {
[K in keyof A]: A[K] extends T ? K : never
}[keyof A]>;
然后您可以在您的情况下将它用于setValue
function:
const setValue = (newValue: T[keyof SubType<T, string>]) => {
const newState = {
...form,
[key]: newValue
}
setForm(newState);
}
给定以下接口Test
- 您应该看到以下类型检查行为:
export interface Test {
stringKey: string;
booleanKey: boolean;
numberKey: number;
}
this.setValue(true); // Err true is not assignable to type string
this.setValue(5); // Err 5 is not assignable to type string
this.setValue('string'); // No Error
唯一的问题是您仍然可以通过 NULL 和 Undefined 而不会出错。 如果您阅读链接文章中的评论,我认为对上述解决方案进行了一些调整 - 如果我有时间,我将对其进行编辑。
希望它有所帮助-感谢您的挑战!
看来这适用于我需要的东西:
function useForm<T>(initialValues: T) {
const [form, setForm] = useState<T>(initialValues);
function field<K extends keyof T>(key: K) {
function setValue<PropType extends T[K]>(newValue: PropType) {
const newState = {
...form,
[key]: newValue,
};
setForm(newState);
};
const value = form[key];
return {
value,
setValue,
};
};
return {
form,
field,
};
}
像这样使用时:
interface Address {
addressId: string;
firstName: string;
lastName: string;
addressType: string;
addressLine1: string;
addressLine2: string;
city: string;
state: string;
country: string;
zipCode: string;
email1: string;
phone1: string;
primary: boolean;
nickName?: string;
}
...
const { field, onSubmit } = useForm<Address>(someInitialAddress);
...
<TextField
field={field('firstName')}
label="First Name"
placeholder="First Name"
/>
This returns the field prop as:
field: {
setValue(value: string): void;
value: string;
};
...
<CheckboxField
field={field('primary')}
label="Use as my primary address for Billing and Shipping"
/>
This returns the field prop as:
field: {
setValue(value: boolean): void;
value: boolean;
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.