【问题标题】:Enforce type safety of a value of a generic type强制泛型类型值的类型安全
【发布时间】:2018-08-26 16:03:38
【问题描述】:

我如何使用泛型来强制一个值的类型为特定类型?

// An example array
const testArr = [
  {
    id: 3,
    name: 'Spaghetto', // NOTE: Type 'string' here
    shouldNotWork: 3.14, // NOTE: Type 'number' here
  },
  {
    id: 5,
    name: 'Bread',
    shouldNotWork: 3.14,
  },
];

这是我试图成为我的映射函数,但我必须附加 as V2 以使 TS 不会抱怨:/

type Mapping<T, U> = (val: T, i: number, arr: T[]) => U;

interface Option<T> {
  value: T;
  label: string; // <- NOTE: Type string is required
}

const typeToOption = <
  T,
  K1 extends keyof T,
  K2 extends keyof T,
  V2 extends T[K2] & string // <- NOTE: 'string' union here to match
>(
  valueK: K1,
  labelK: K2,
): Mapping<T, Option<T[K1]>> => (item: T): Option<T[K1]> => ({
  value: item[valueK],
  label: item[labelK] as V2,
});

我希望 TS 允许我这样做

const result = testArr.map(typeToOption('id', 'name'));

...但不是这个

const result = testArr.map(typeToOption('id', 'shouldNotWork'));

如何让 TS 抱怨后者?

【问题讨论】:

    标签: typescript typescript-generics


    【解决方案1】:

    我想你想这样输入typeToOption()

    const typeToOption = <
      T extends Record<K2, string>,
      K1 extends keyof T,
      K2 extends keyof T,
    >(
      valueK: K1,
      labelK: K2,
    ): Mapping<T, Option<T[K1]>> => (item: T): Option<T[K1]> => ({
      value: item[valueK],
      label: item[labelK],
    });
    

    TypeScript 允许您在泛型参数中执行一些“循环”类型约束。所以在这种情况下,我们根本不需要指定V2(因为它没有做任何工作),我们只需要T extends Record&lt;K2, string&gt;,这意味着T类型必须有一个string值属性在键K2。这足以满足您的要求:

    const result = testArr.map(typeToOption('id', 'name')); // okay
    
    const result = testArr.map(typeToOption('id', 'shouldNotWork')); // error
    // [ts] Argument of type '"id"' is not assignable to 
    // parameter of type '"shouldNotWork"'.
    

    虽然这个错误有点令人眼花缭乱,但至少它是一个错误。 (如果重要的话:类型推断失败会导致有趣的事情发生。T 回退到Record&lt;'shouldNotWork', string&gt;,相当于{shouldNotWork: string},而keyof T 只是'shouldNotWork',因此K1 extends'shouldNotWork'` . 哦,好吧。)

    希望有所帮助;祝你好运!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-06-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-17
      • 1970-01-01
      相关资源
      最近更新 更多