Typescript 元组,其中后续元素的类型依赖于前一个元素的值

Typescript 元组,其中后续元素的类型依赖于前一个元素的值,typescript,generics,types,tuples,Typescript,Generics,Types,Tuples,我想我有一个简单的问题,但我也不确定这在TypeScript中是否可行 本质上,我想定义一个元组类型,它有两个元素,第二个元素取决于第一个元素的值 作为一个例子,我想创建一个类型,其中第一个元组元素是接口的键,第二个元组元素随后绑定到该属性的类型。例如: interface ExampleI { a: number; b: string; } const one: KeyedTuple<ExampleI> = ["a", 34]; // good const two: Ke

我想我有一个简单的问题,但我也不确定这在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

这可能吗?如果是,怎么做

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]
是实现这一点的一种方法,我更赞成使用函数来实现这一点,而不是记住写出冒号或按正确类型转换

除非知道键,否则代码将无法工作。它不能从变量中推断,但可以从函数中推断

IE您的代码必须更改为objkeed=[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

从概念上讲,我认为您希望KeyedTuple是keyof T中所有K的[K,T[K]]元组的集合。这可以通过和类型实现,如下所示:

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]
const one: KeyedTuple<ExampleI> = ["a", 34]; // okay
const two: KeyedTuple<ExampleI> = ["a", "not a number"]; // error
const three: KeyedTuple<ExampleI> = ["b", 47]; // error
one[1].toFixed(); // okay, remembers one[1] is a number