Essentially I want to ensure that an object argument contains all of the required properties, but can contain any other properties it wants. For example:
function foo(bar: { baz: number }) : number {
return bar.baz;
}
foo({ baz: 1, other: 2 });
But this results in:
Object literal may only specify known properties, and 'other' does not exist in type '{ baz: number; }'.
unknown is the type-safe counterpart of any . Anything is assignable to unknown , but unknown isn't assignable to anything but itself and any without a type assertion or a control flow based narrowing. Likewise, no operations are permitted on an unknown without first asserting or narrowing to a more specific type.
In TypeScript, object is the type of all non-primitive values (primitive values are undefined , null , booleans, numbers, bigints, strings). With this type, we can't access any properties of a value.
In Typescript, any value can be assigned to unknown, but without a type assertion, unknown can't be assigned to anything but itself and any. Similarly, no operations on an unknown are allowed without first asserting or restricting it down to a more precise type.
Yes, you can. Try this:
interface IBaz { baz: number; [key: string]: any; } function foo(bar: IBaz) : number { return bar.baz; } foo({ baz: 1, other: 2 });
Well, i hate answering my own questions, but the other answers inspired a little thought... This works:
function foo<T extends { baz: number }>(bar: T): void { console.log(bar.baz); } foo({baz: 1, other: 2});
If the known fields are coming from a generic type the way to allow wildcards is with T & {[key: string]: unknown}
, any fields that are known must fit with the type's constraints and other fields are allowed (and considered type unknown
)
Here is a sample:
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
Then if you have a generic type T
you can allow wildcard fields with WithWildCards<T>
Note that extra properties are not marked as errors if the object is coming from anything other than an object literal, TS is just telling you that with the typing putting that property in the literal is extraneous.
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
If you want to allow unknown properties for the entire object, you can use Record
function doStuff(payload: Record<string|number, unknown>): Record<string|number, unknown> {
return { anyProp: 'anyValue' }
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With