[英]How to define a property on a utility type?
所以我有一个将数组作为参数的函数。 该数组包含未知对象。 我们确实知道对象都是一样的,所以换句话说,数组只能接受一种类型的对象,但对象类型是动态的,它几乎可以是任何东西。 我说几乎是因为我们知道了一点信息:对象都有一个 name 属性。
该函数的数组参数接受一个类型相同但类型未知的对象数组。 我们所知道的是该类型包含一个名称属性,因此; 我们知道每个对象都有一个 name 属性。
type ObjType = {
name: string;
[key: string]: any;
}
type NewObj = {
[key: string]: {}
}
export function nameArray(arrParam: ObjType[]){
let obj: NewObj = {};
arrParam.forEach((item, index)=>{
obj[item.name] = item;
});
return obj;
}
因为我们知道对象都有一个 name 属性,所以我们可以使用它为键分配适当的名称,然后将对象分配给该键。 这样,我们就有了可枚举的数组,以及一个可以用来按名称引用对象的对象。
好吧,我撒谎了,老实说,我不是故意的。 该功能确实有效,但我认为奇妙的是措辞的错误选择。 类型推断没有流经该函数,因此,即使它有效,我在使用它时也没有得到类型信息,这很糟糕,因为 TS 需要做很多额外的工作,如果我不这样做又有什么意义在脚本的复杂方面结束类型。
我在一个真实的项目中使用它。 这是我测试过的文档。
import { nameArray } from './util-fn.mjs';
type StrGenArg = {
// INDEX @00
name: string,
arg: string,
code: string | number;
}
type StrGenArgs = StrGenArg[];
export const strGenArg: StrGenArgs = [
{ // INDEX @00 | "escOpen"
name: 'escOpen',
arg: '%%',
code: '\x1b'
},
{ // INDEX @01 | "escClose"
name: 'escClose',
arg: '%%',
code: '\x1b'
},
{ // INDEX @02 | "reset"
name: 'reset',
arg: '0',
code: 0
},
{ // INDEX @03 | "red"
name: 'red',
arg: '%r',
code: 31
},
{ // INDEX @04 | "green"
name: 'green',
arg: 'g',
code: 32
},
{ // INDEX @05 | "yellow"
name: 'yellow',
arg: 'y',
code: 33
}
];
export const args = nameArray(strGenArg);
正如我所说,它有效; 喜欢,我做以下。
console.log(args.yellow)
它打印黄色,红色和绿色以及其余对象相同,但是,正如我已经说过的:没有类型!
我尝试使用这样的实用程序类型。
function nameArray<T>(arrParam: T[]){
let obj: NewObj = {};
arrParam.forEach((item, index)=>{
obj[item.name] = item;
});
}
但是当我以这种方式编写函数时,它不知道T
具有命名属性,因此,TSC 显示错误,并且不会编译。
有没有写这个函数,我可以得到类型推断?
您需要将T
限制为始终具有属性name
。 这将强制传递给函数的数组的任何元素都必须具有name
属性。
function nameArray<T extends { name: string }>(arrParam: T[]){ /* ... */ }
但这并不能完全解决您的问题。 您说您例如想要访问args.yellow
。 那么我们该怎么做呢?
这有点复杂。
首先,我们必须将as const
添加到strGenArgs
,这样我们就不会在这里丢失类型信息:
export const strGenArg = [
{ // INDEX @00 | "escOpen"
name: 'escOpen',
arg: '%%',
code: '\x1b'
},
{ // INDEX @01 | "escClose"
name: 'escClose',
arg: '%%',
code: '\x1b'
},
{ // INDEX @02 | "reset"
name: 'reset',
arg: '0',
code: 0
},
{ // INDEX @03 | "red"
name: 'red',
arg: '%r',
code: 31
},
{ // INDEX @04 | "green"
name: 'green',
arg: 'g',
code: 32
},
{ // INDEX @05 | "yellow"
name: 'yellow',
arg: 'y',
code: 33
}
] as const;
我们还介绍了通用类型K
,它将保存所有可能的名称值。 之后我们返回一个Record<K, StrGenArg>
。
type ExtractName<T extends { name: string }[]> = T[number]["name"]
function nameArray<
T extends { name: string }[],
K extends ExtractName<T>
>(arrParam: readonly [...T]): Record<K, StrGenArg> {
let obj: Record<string, any> = {};
arrParam.forEach((item, index)=>{
obj[item.name] = item;
});
return obj
}
现在打字工作:
export const args = nameArray(strGenArg);
args.yellow // works with typing
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.