Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

typescript - Interface is allowing extra property when it is used as return type of a function

An inteface seems to accept extra property(ies) when it is assigned as a return of a function via a type.

For example if I have an empty interface named MyInterface, a type for a function : type MyFunction = () => MyInterface; and a function const myFunction: MyFunction = () => ({ foo: 'bar' }) it does not throw any error for the foo property.

Here's some examples :

// No 'age' property
interface Human {
  name: string;
}

const human: Human = {
  name: '',
  age: 0 // Error
}

type HumanCreator = (name: Human['name'], age: number) => Human;

const humanCreator: HumanCreator = (name, age) => ({
  name,
  age // No error. Why?
});

const humanCreatorr: HumanCreator = (name, age): Human => ({
  name,
  age // Error
});

const humanCreatorrr = (): Human => ({
  name: '',
  age: 0 // Error
});

Why when I type the variable humanCreator with HumanCreator it does not care if I add extra property(ies) to the returned object?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

An inteface seems to accept extra property(ies) when it is assigned as a return of a function via a type.

In general, TypeScript uses structural typing, so it is perfectly fine to assign an object with additional properties to a Human interface.

const lui = {
  name: "Lui",
  age: 40
}

const human: Human = lui // works, 

You can assign lui to variable human with type Human, because typeof lui is a sub-type and therefore has the same/compatible property members.

An exception to this rule are excess property checks for "freshly created object literals", that are intended as developer aid and prohibit extra properties to be added. The general thought here is, that you exactly know what properties you want, when you define a direct object literal with no other indirection (access of variables etc. to get that object value).

Excess property checks require an immediately following explicit type annotation at the variable, property or function dealing with the fresh object literal in order to work. Otherwise the object literal type doesn't count as "fresh" anymore (its type is widened). Let's check your examples to illustrate the concept.

const humanCreator: HumanCreator = (name, age) => ({
  name,
  age // No error. Why?
});

You can see this as an assignment of a type compatible function to the variable with type HumanCreator. The compiler looks at the function expression (name, age) => ({ name, age }), infers parameter types and makes sure that its return type is compatible to the variable type. And indeed - {name: string; age:number} return type is assignable to Human (structural typing).

const humanCreatorr: HumanCreator = (name, age): Human => ({
  name,
  age // Error
});

const humanCreatorrr = (): Human => ({
  name: '',
  age: 0 // Error
});

These cases are different, as you immediately annotate the functions with Human return type. There is no type inference for the return type necessary for the compiler. tl;dr To enable excess property checks, annotate an explicit type for your object literal as close as possible.

Further links


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...