Typescript的新手,我有一个关于键入对象数组的快速问题。 现在就可以了:
const my_array = [{
foo: "hello",
bar: "Typescript"
},
{
foo: "goodbye",
bar: "JavaScript"
}
];
默认情况下,它将推断类型为
的my_array{foo:string; bar:string;}[]
我的要求:我希望输入更准确的信息,例如:
{foo: "hello" | "goodbye"; bar: // value according to foo }
我还希望有一个 DRY 解决方案,并且只定义一次我的foo
和bar
值以提高可维护性
答案 0 :(得分:2)
您可以为每种记录类型定义类型:
type Alpha = {"foo": "alpha", "bar": number}
type Beta = {"foo": "beta", "bar": string}
然后,您可以定义一个数组,该数组是Alpha
或Beta
(称为联合类型)的列表
let arr: (Alpha | Beta)[] = some_array();
遍历数组时,TypeScript将字段的类型识别为
for (let el of arr) {
// el.foo is "alpha" | "beta"
// el.bar is number | string
但是,如果您检查.foo
标记,TypeScript将缩小.bar
的类型,因为它实际上知道每个元素都是Alpha
或Beta
:>
if (el.foo == "alpha") {
// el.bar is number
} else {
// el.bar is string
}
}
答案 1 :(得分:2)
当这些值包含为数组元素或对象属性时,将这些值哄骗到编译器以推断文字类型是很棘手的。这是一种解决方法:
type Narrowable = string | number | boolean | object | {} | null | undefined | void;
const tupleOfNarrowObjects =
<V extends Narrowable, O extends { [k: string]: V }, T extends O[]>(...t: T) => t;
const my_array = tupleOfNarrowObjects(
{
foo: "hello",
bar: "Typescript"
}, {
foo: "goodbye",
bar: "JavaScript"
}
);
如果您这样做,my_array
现在将被推断为以下类型:
const my_array: [{
foo: "hello";
bar: "Typescript";
}, {
foo: "goodbye";
bar: "JavaScript";
}]
尽可能地狭窄:一个由字符串文字组成的对象的元组。因此,编译器知道my_array[0].foo
是"hello"
。而且,如果您遍历my_array
,则编译器会将每个元素都视为discriminated union。
工作原理:
Narrowable
类型与unknown
基本相同,不同之处在于编译器将其视为包含string
和number
的并集。如果您有一个通用类型参数V extends N
,其中约束N
是string
或number
或包含它们的并集,则V
将被推断为文字输入是否可以。
通常,将类型参数O
推断为对象类型时,它不会将属性类型的范围缩小为文字。但是,如果将O
约束为一种索引签名类型,而其值类型可以缩小为文字,例如{ [k: string]: V }
,则它将。
最后,当使用约束为数组类型的泛型类型的rest参数时,编译器将尽可能推断该参数的元组类型。
将所有这些放在一起,如果可能的话,以上tupleOfNarrowObjects
会将其参数推断为文字属性对象的元组。这很丑陋(单个参数有三个类型的参数),但它的工作原理是:您不必重复自己。
希望对您有帮助。祝你好运。
答案 2 :(得分:0)
从 3.7.5 版本开始的当前 Typescript 实现,为推导编译时常量窄参数类型提供了有限的支持,但特定的构造允许它:
type Narrowable = "" | 0 | true | false | symbol | object | undefined | void | null | {} | [Narrowable] | { [k in keyof any]: Narrowable }
function gen<T extends Narrowable>(x: T): T { return x };
const f = gen(["www", 1,2,3,[1,2,3,[5,"qqq"],"str"],4, {a:5,b:{c:{a:54,b:"www"}}}])