Can you explain why when I pass incorrect variable type to the function ts do not emit type error?
export class CreateCategoryDto implements Omit<Category, 'id' | 'children' | 'parent'> {
name: string;
parentId: number;
}
export async function createCategory(dto: CreateCategoryDto) {
return getRepository(Category).save(dto);
}
const data = { id: 555, name: 'sdfsdf', parentId: 55 };
ctx.body = {
data1: await createCategory(data), // not emit
data: await createCategory({ id: 555, name: 'sdfsdf', parentId: 55 }), // emit that params must be without id
};
This has to do with excess property checking and object literal freshness.
When is an object literal considered fresh might you ask?
An object literal is considered fresh when Typescript infers its type for you and there was neither type assertion nor was the object literal assigned to a variable.
// using type assertion, this works
data: await createCategory({ id: 555, name: 'sdfsdf', parentId: 55 } as CreateCategoryDto)
In the first case, you assigned it to a variable, so the freshness dissapeared and there was no excess property checking.
const data = { id: 555, name: 'sdfsdf', parentId: 55 }; // you assigned it to a variable
data1: await createCategory(data)
However, in the second case you passed the object literal directly to the function without assigning it to a variable first, so Typescript infered its type: the object literal is fresh.
data: await createCategory({ id: 555, name: 'sdfsdf', parentId: 55 }) // this object is fresh
And when that's the case, there's something we call excess property checking, which works as follows: when you try to assign a fresh object literal type T to another type U, and T has properties that aren't in U, Typescript complains. This is useful for detecting misspellings.
Quoting from the docs:
[...] TypeScript takes the stance that there’s probably a bug in this code. Object literals get special treatment and undergo excess property checking when assigning them to other variables, or passing them as arguments. If an object literal has any properties that the “target type” doesn’t have, you’ll get an error [...]
This also produces an error:
var categoryDto: CreateCategoryDto = { id: 555, name: 'sdfsdf', parentId: 55 }
whereas this doesn't:
var categoryDto = { id: 555, name: 'sdfsdf', parentId: 55 }
var test: CreateCategoryDto = categoryDto
Object types are covariant in their members (you want a T or a subtype of T), extra properties are insignificant. This can lead to unsafe behavior but the authors wanted to strike a balance between ease of use and safety. Here, there was excess property checking involved due to the object literal being fresh.
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