我有一个这样的函数
function transform(obj) {
const returnedObj = { custom: {} };
for (key in obj.wrap.custom) {
returnedObj.custom[key] = obj.wrap.custom[key];
}
return returnedObj;
}
描述类型的正确方法是什么?我已经试过了
interface ITransformingObject {
wrap: {
custom: {[key: string]: string}
}
}
interface IReturnedObject {
custom: ITransformingObject['wrap']['custom']
}
function transform(obj: ITransformingObject): IReturnedObject {
const returnedObj = { custom: {} };
for (const key in obj.wrap.custom) {
returnedObj.custom[key] = obj.wrap.custom[key];
}
return returnedObj;
}
const a = {
wrap: {
custom: {
test: 'test'
}
}
}
const b = transform(a);
但我不确定它是否正确。例如,智能感知看不到a.custom
的属性。我可以更好地描述返回类型来定义a.custom
的键必须与a.wrap.custom
的键相同吗?
为了跟踪custom
属性中的特定对象类型,需要使用泛型,如下所示:
interface ITransformingObject<T extends object> {
wrap: {
custom: T
}
}
interface IReturnedObject<T extends object> {
custom: T
}
function transform<T extends object>(obj: ITransformingObject<T>): IReturnedObject<T> {
const returnedObj = { custom: {} } as IReturnedObject<T>;
for (const key in obj.wrap.custom) {
returnedObj.custom[key] = obj.wrap.custom[key];
}
return returnedObj;
}
这里ITransformingObject<T>
有一个wrap
属性和一个custom
属性,类型为T
,对于一些类似于你指定的T
对象。IReturnedObject<T>
是相同的,但没有wrap
包装器。那么transform()
也是泛型的;对于某些T
,它的参数类型为ITransformingObject<T>
,然后对于相同的T
返回IReturnedObject<T>
类型的值。
还需要注意的是,为了使编译没有错误,我需要断言returnedObject
是IReturnedObject<T>
类型,因为它最初不是为真(当然在初始化时,{}
的值不太可能是T
类型)。
现在,当您调用transform()
时,编译器将根据您传入的值的类型为您推断类型参数T
:
const a = {
wrap: {
custom: {
test: 'test'
}
}
}
const b = transform(a);
/* function transform<{
test: string;
}>(obj: ITransformingObject<{
test: string;
}>): IReturnedObject<{
test: string;
}> */
看T
是如何被推断为{test: string}
的,因此b
的类型是IReturnedObject<{test: string}>
。这意味着编译器现在知道b.custom
中应该存在或不应该存在哪些属性:
console.log(b.custom.test.toUpperCase()); // compiles fine, "TEST"
b.custom.nope // compiler error, nope does not exist on {test: string}
Playground链接到代码