繁体   English   中英

有没有办法从作为泛型传递的接口推断特定值的类型?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM