你能在打字稿中声明一个允许未知属性的对象字面量类型吗?

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)