To make it simple, I have an issue with Typescript's "Excess Property Checks" behavior. I would like to be sure that an object with extra properties is not be accepted by TypeScript.
In my example of a simple interface I could simply pick the available data, but I have a lot of properties and I would like to avoid filtering them on runtime, is there a way?
Here you can find an example code I made for this topic :
TypeScript Playground
type LayoutType {
margin: number;
}
const badData = {
margin: 23,
padding: 23,
}
function func(param: LayoutType) {
console.log(param);
// Here I want to use property being sure param only contains LayoutType property
}
// OK
func({ margin: 42 })
// OK : padding is detected as unwanted property
func({ margin: 42, padding: 32 })
// KO : bad data shouldn't fit
func(badData)
/* SAME */
// OK : padding is detected as unwanted property
const test1: LayoutType = { margin: 42, padding: 32 };
// KO : bad data shouldn't fit
const test2: LayoutType = badData;
Typescript can't restrict extra properties Unfortunately this isn't currently possible in Typescript, and somewhat contradicts the shape nature of TS type checking.
Use the Partial utility type to make all of the properties in a type optional, e.g. const emp: Partial<Employee> = {}; . The Partial utility type constructs a new type with all properties of the provided type set to optional. Copied!
TypeScript introduced a new type never , which indicates the values that will never occur. The never type is used when you are sure that something is never going to occur. For example, you write a function which will not return to its end point or always throws an exception.
Interface is a structure that defines the contract in your application. It defines the syntax for classes to follow. Classes that are derived from an interface must follow the structure provided by their interface. The TypeScript compiler does not convert interface to JavaScript.
Sounds like you want an Exact
type. Typescript doesn't come with one, but it's easy to make:
type Exact<A, B> = A extends B
? B extends A
? A
: never
: never
This basically says that if and A extends B
and B extends A
then the types are identical, neither are a subset or superset of the other. So it should allow that type through. If they are not identical, then the type is never
which prevents that type from being allowed.
Now you just need to make your function generic, and enforce that argument to exactly the right type:
function func<T>(param: Exact<T, LayoutType>) {
console.log(param);
}
func(badData)
// Argument of type '{ margin: number; padding: number; }'
// is not assignable to parameter of type 'never'.
Playground
More relevant reading here in Typescript issue #12936
Lastly, the reason that an object literal doesn't work, but an object variable does is that the literal is being constructed for a particular type. Typescript can't know know about the extra properties because there is no type information for those properties. So the typescript program can't use those properties, because they aren't declared to exist.
However, when the object is a variable and the extra properties are known, then it is a separate but compatible type. The extra properties may not be used in a function that only accepts the narrow type, but in other code that knows about the wider type the properties can be used.
This is why this is valid:
const obj1 = { a: 1, b: 2 }
const obj2: { a: number } = obj1
console.log(obj1.b) // b can still be accessed
But this is not:
const obj1: { a: number } = { a: 1, b: 2 }
// ^ type error
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