TypeScript - 数组的约束

问题描述 投票:0回答:1

我有以下(example-)数组:

[
  'test-string', 
  foo => ({ foo }), 
  'other-string', 
  bar => ({ bar })
]

使用(example-)接口

interface MyValues { foo: string; bar: string; }

期望此数组类型的函数必须确保所有函数的结果的统一实现完整的接口。那可能吗?目前,我有:

type Fn<Values> = (part: string) => { [key in keyof Values]?: string }
type Item<Values> = string | Fn<Values>;

function extract<Values>(items: Item<Values>[]) {
  const values = {} as Values;
  // (...)
  return values;
}

但是,此类型仅检查所有函数是否返回与Values的键匹配的对象,而不是所有键最终都存在。

我不太确定使用TypeScript是否可以进行此检查,我发现this answer也用于类型的“计算”,但我不确定这是否适用于此用例。

typescript generics types typescript-typings static-typing
1个回答
0
投票

我非常有信心你没有可以编写的类型,其成员是你想要的形式的数组。如果让TypeScript推断数组的元素类型作为其成员类型的并集,则可以验证元素类型是否显示为覆盖整个接口:

interface MyValues { foo: string; bar: string; }

// From jcalz, https://stackoverflow.com/a/50375286
type UnionToIntersection<U> = 
  (U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never

type Fn<Values> = (part: string) => { [key in keyof Values]?: string }
type Item<Values> = string | Fn<Values>;
type CheckComplete<Values, T extends Item<Values>> =
  // note: ReturnType is distributive.
  UnionToIntersection<ReturnType<Exclude<T, string>>> extends
  { [key in keyof Values]: string } ? unknown : never;

function extractFactory<Values>() {
  return function<T extends Item<Values>>(items: T[] & CheckComplete<Values, T>) {
    const values = {} as Values;
    // (...)
    return values;  
  };
}

const extract = extractFactory<MyValues>();

const a = [
  'test-string', 
  foo => ({ foo }), 
  'other-string', 
  bar => ({ bar })
];
extract(a);  // OK

const b = [
  'test-string', 
  foo => ({ foo }), 
  'other-string'
];
extract(b);  // Error

但是,使用注释可以轻松地绕过检查,该注释将元素类型设置为union,而不是所有成员实际出现在数组中:

extract<string
  | ((arg: string) => {foo: string})
  | ((arg: string) => {bar: string})>(b);  // Wrong but no error
© www.soinside.com 2019 - 2024. All rights reserved.