问题
According to docs, "Type compatibility in TypeScript is based on structural subtyping". So this is possible:
type Person: {
name: string;
}
const developer = {
name: 'Joe',
language: 'Typescript',
}
// this is ok because Person is a subtype of typeof developer
const otherDeveloper: Person = developer; // who writes code like that?!
This has many consequences, one of many is that you lose type information when using Object.keys:
// "keys" type is array of strings not `name` literal as this would be of course wrong because in runtime "keys" is ['name', 'language']
const keys = Object.keys(otherDeveloper);
So I was trying to find the reason for this subtyping in TS docs as they promise but I couldn't find one
The places where TypeScript allows unsound behavior were carefully considered, and throughout this document we’ll explain where these happen and the motivating scenarios behind them.
The only place where this maybe would be helpful for me would be a function that expects object of narrower type, for example:
function getName(person: Person) {
return person.name;
}
getName(developer); // works fine because of subtyping
I personally don't see a big issue if you'd have to use casting in that case:
getName(developer as Person);
Are there other examples that I might be missing?
回答1:
The reason Typescript uses structural typing is that JS is duck typed.
So you could do what you wrote above in JS, ideally you can do it in TS just in a more type safe way. Javascript does not care about the declared types of object, there is no such concept in JS, it only cares about the properties objects have at runtime. Thus any object could be passed into your getName
function and as long as the name property existed, the function would arguably function correctly.
Moreover since JS has object literals that do not belong to a specific class it would be difficult to specify inheritance relations explicitly everywhere. Making type relations explicit would have make TS less atractive to JS developers. Under a structural type system the types mostly work our and you get a lot of benefit from it without having to be very explicit.
There are ways to make get around structural typing and mimic a normative type in typescript either by using private properties (ex) or using branded types (ex)
来源:https://stackoverflow.com/questions/55180304/why-does-typescript-allow-for-subtyping