我想我有一个简单的问题,但我也不敢肯定在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
这可能吗?如果可以,怎么办?
答案 0 :(得分:1)
从概念上讲,我认为您希望KeyedTuple<T>
中所有[K, T[K]]
的{{1}}成为K
元组的union。可以使用mapped和lookup类型来实现,就像这样:
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
希望有所帮助;祝你好运!
答案 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