你能在打字稿中声明一个允许未知属性的对象字面量类型吗?
Can you declare a object literal type that allows unknown properties in typescript?
基本上我想确保对象参数包含所有必需的属性,但可以包含它想要的任何其他属性。例如:
function foo(bar: { baz: number }) : number {
return bar.baz;
}
foo({ baz: 1, other: 2 });
但这会导致:
Object literal may only specify known properties, and 'other' does not exist in type '{ baz: number; }'.
这可以通过为函数参数定义类型定义来最轻松地完成。下面是一个内联类型定义的例子:
function foo(bar: { baz: number }) : number {
return bar.baz;
}
const obj = { baz: 1, other: 2 };
foo(obj);
是的,你可以。试试这个:
interface IBaz {
baz: number;
[key: string]: any;
}
function foo(bar: IBaz) : number {
return bar.baz;
}
foo({ baz: 1, other: 2 });
好吧,我讨厌回答我自己的问题,但其他答案激发了我的一点思考......这有效:
function foo<T extends { baz: number }>(bar: T): void {
console.log(bar.baz);
}
foo({baz: 1, other: 2});
如果已知字段来自通用类型,则允许通配符的方式是使用 T & {[key: string]: unknown}
,任何已知字段都必须符合类型的约束,并且允许其他字段(并被视为类型 unknown
)
这是一个示例:
type WithWildcards<T> = T & { [key: string]: unknown };
function test(foo: WithWildcards<{baz: number}>) {}
test({ baz: 1 }); // works
test({ baz: 1, other: 4 }); // works
test({ baz: '', other: 4 }); // fails since baz isn't a number
然后如果你有一个通用类型 T
你可以允许通配符字段 WithWildCards<T>
请注意,如果对象来自对象文字以外的任何内容,则不会将额外的属性标记为错误,TS 只是告诉您,在文字中输入 属性 是无关紧要的。
Here are some other cases where extra properties are and aren't allowed
interface Foos{
a?: string
b?: string
}
type WithWildcards<T> = T & { [key: string]: unknown };
declare function acceptFoos(foo: Foos): void;
declare function acceptWild(foo: WithWildcards<Foos>):void
acceptFoos( {a:'', other: ''}) // ERROR since the property is extraneous
const data = {a:'', other: ''}
acceptFoos( data) // allowed since it is compatible, typescript doesn't force you to remove the properties
const notCompat = {other: ''}
acceptFoos(notCompat) //ERROR: Type '{ other: string; }' has no properties in common with type 'Foos'
acceptFoos({a:'', ...notCompat}) // this is also allowed
acceptWild(notCompat) // allowed
如果要允许整个对象的未知属性,可以使用Record
function doStuff(payload: Record<string|number, unknown>): Record<string|number, unknown> {
return { anyProp: 'anyValue' }
}
当使用 unknown
类型时,您可以使用 narrowing
的概念来检查您希望从您正在经历的值中获得的类型,并根据您的需要操作这些值
例如
const messages: string []=Object.values(obj).map(val: unknown=>typeof obj==='object'?obj!['message']:obj)
基本上我想确保对象参数包含所有必需的属性,但可以包含它想要的任何其他属性。例如:
function foo(bar: { baz: number }) : number {
return bar.baz;
}
foo({ baz: 1, other: 2 });
但这会导致:
Object literal may only specify known properties, and 'other' does not exist in type '{ baz: number; }'.
这可以通过为函数参数定义类型定义来最轻松地完成。下面是一个内联类型定义的例子:
function foo(bar: { baz: number }) : number {
return bar.baz;
}
const obj = { baz: 1, other: 2 };
foo(obj);
是的,你可以。试试这个:
interface IBaz {
baz: number;
[key: string]: any;
}
function foo(bar: IBaz) : number {
return bar.baz;
}
foo({ baz: 1, other: 2 });
好吧,我讨厌回答我自己的问题,但其他答案激发了我的一点思考......这有效:
function foo<T extends { baz: number }>(bar: T): void {
console.log(bar.baz);
}
foo({baz: 1, other: 2});
如果已知字段来自通用类型,则允许通配符的方式是使用 T & {[key: string]: unknown}
,任何已知字段都必须符合类型的约束,并且允许其他字段(并被视为类型 unknown
)
这是一个示例:
type WithWildcards<T> = T & { [key: string]: unknown };
function test(foo: WithWildcards<{baz: number}>) {}
test({ baz: 1 }); // works
test({ baz: 1, other: 4 }); // works
test({ baz: '', other: 4 }); // fails since baz isn't a number
然后如果你有一个通用类型 T
你可以允许通配符字段 WithWildCards<T>
请注意,如果对象来自对象文字以外的任何内容,则不会将额外的属性标记为错误,TS 只是告诉您,在文字中输入 属性 是无关紧要的。
Here are some other cases where extra properties are and aren't allowed
interface Foos{
a?: string
b?: string
}
type WithWildcards<T> = T & { [key: string]: unknown };
declare function acceptFoos(foo: Foos): void;
declare function acceptWild(foo: WithWildcards<Foos>):void
acceptFoos( {a:'', other: ''}) // ERROR since the property is extraneous
const data = {a:'', other: ''}
acceptFoos( data) // allowed since it is compatible, typescript doesn't force you to remove the properties
const notCompat = {other: ''}
acceptFoos(notCompat) //ERROR: Type '{ other: string; }' has no properties in common with type 'Foos'
acceptFoos({a:'', ...notCompat}) // this is also allowed
acceptWild(notCompat) // allowed
如果要允许整个对象的未知属性,可以使用Record
function doStuff(payload: Record<string|number, unknown>): Record<string|number, unknown> {
return { anyProp: 'anyValue' }
}
当使用 unknown
类型时,您可以使用 narrowing
的概念来检查您希望从您正在经历的值中获得的类型,并根据您的需要操作这些值
例如
const messages: string []=Object.values(obj).map(val: unknown=>typeof obj==='object'?obj!['message']:obj)