元组,后继元素的类型取决于前一个元素的值

时间:2019-08-21 22:06:55

标签: typescript generics types tuples

我想我有一个简单的问题,但我也不敢肯定在TypeScript中是否可以实现。

基本上,我想定义一个具有两个元素的元组类型,第二个元素取决于第一个元素的值。

作为一个例子,我想创建一个类型,其中第一个元组元素是接口的键,然后将第二个元组元素绑定到该属性的类型。例如:

interface ExampleI {
  a: number;
  b: string;
}

const one: KeyedTuple<ExampleI> = ["a", 34]; // good
const two: KeyedTuple<ExampleI> = ["a", "not a number"]; // bad
const three: KeyedTuple<ExampleI> = ["b", 47]; // bad

我尝试执行以下操作:

type KeyedTuple<T, K extends keyof T> = [K, T[K]];

这几乎可行,但是编译器仅考虑K的类型,而不考虑K的值,因此第二个元素始终的类型为number | string

这可能吗?如果可以,怎么办?

2 个答案:

答案 0 :(得分:1)

从概念上讲,我认为您希望KeyedTuple<T>中所有[K, T[K]]的{​​{1}}成为K元组的union。可以使用mappedlookup类型来实现,就像这样:

keyof T

让我们测试一下:

type KeyedTuple<T> = { [K in keyof T]: [K, T[K]] }[keyof T];

它可以为您提供所要求的行为:

interface ExampleI {
  a: number;
  b: string;
}

type KeyedTupleExampleI = KeyedTuple<ExampleI>;
// type KeyedTupleExampleI = ["a", number] | ["b", string]

此外,由于赋值在联合类型上充当type guards,因此编译器将记住变量是哪个键/值对:

const one: KeyedTuple<ExampleI> = ["a", 34]; // okay
const two: KeyedTuple<ExampleI> = ["a", "not a number"]; // error
const three: KeyedTuple<ExampleI> = ["b", 47]; // error

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

Link to code

答案 1 :(得分:0)

const keyedTuple = <T, K extends keyof T>(obj: T, key: K): [T, T[K]] => {
    return [obj, obj[key]]
}

interface IPerson {
    name: string;
    age: number
}
declare const Person: IPerson
const test = keyedTuple(Person, "name") // [Person, string]

是实现这一目标的一种方法,我更喜欢拥有一个实现此目标的功能,而不是记住写出一个冒号或“ as”类型转换为正确的类型。

除非知道该键,否则您的代码将无法工作,该键不能从变量中推断出来,而可以从函数中推断出来。

IE您的代码必须更改为类似ObjKeyed<OBJ, KEY> = [Obj, Key]

编辑:类型:

type KeyedTuple<T, K extends keyof T> = [K, T[K]];

interface ExampleI {
  a: number;
  b: string;
}

const one: KeyedTuple<ExampleI, "a"> = ["a", 34]; // good
const two: KeyedTuple<ExampleI, "a"> = ["a", "not a number"]; // bad
const three: KeyedTuple<ExampleI, "b"> = ["b", 47]; // bad
相关问题