Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to understand subtypes, inverters and covariates in TypeScript

2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article mainly introduces "how to understand subtypes, inverters and covariates in TypeScript". In daily operation, I believe many people have doubts about how to understand subtypes, inverters and covariates in TypeScript. Xiaobian consulted all kinds of materials and sorted out simple and easy-to-use methods of operation. I hope it will be helpful for you to answer the doubts of "how to understand subtypes, inverters and covariates in TypeScript!" Next, please follow the editor to study!

Preface

There are many places in TypeScript involving the concepts of child type subtype and parent type supertype. If you don't understand these concepts, you may be unable to start by reporting mistakes, or you may see that someone else can write this when writing some complex types, but you don't know why it works.

Subtype

For example, consider the following APIs:

Interface Animal {age: number} interface Dog extends Animal {bark (): void}

In this example, Animal is the parent of Dog, Dog is the subtype of Animal, and the subtype has more and more specific attributes than the parent type.

In the type system, more types of attributes are subtypes.

In set theory, a set with fewer attributes is a subset.

That is, it is intuitively easy to get confused that a subtype is a superset of the parent type, while the parent type is a subset of the subtype.

It is critical to remember that child types are more specific than parent types.

Assignable assignable

Assignable is a very important concept in the type system. When you assign one variable to another, check whether the types of the two variables can assign values to each other.

Let animal: Animal let dog: Dog animal = dog / / ✅ ok dog = animal / / ❌ error! Missing property 'bark' on animal instance

As can be seen from this example, animal is a "broader" type with fewer attributes, so more "specific" subtypes can be assigned to it, because you know that there is only age on animal, you will only use this attribute, dog has all the types that animal has, and assigning values to animal will not cause type safety problems.

Conversely, if dog = animal, then the subsequent user will expect to have the bark property on the dog, which will cause a runtime crash when he calls dog.bark ().

In terms of valuability, the subtype can be assigned to the parent type, that is, the parent type variable = the child type variable is safe because the subtype covers all the attributes owned by the parent type.

When I first learned it, I found it strange that statements like T extends {} could extends an empty type and hold when passing any type. When we understand the above knowledge points, this problem will naturally be solved.

The application in the function

Suppose we have a function like this:

Function f (val: {a: number; b: number})

There are two variables:

Let val1 = {a: 1} let val2 = {a: 1, b: 2, c: 3}

Calling f (val1) will report an error, obviously because of the lack of attribute b, while the function f is likely to access the b property and do some operations, such as b.substr (), which will lead to a crash.

According to the knowledge points above, the corresponding type of val1 is {a: number}, which is the parent type of {a: number, b: number}. Calling f (val1) is actually equivalent to assigning the formal parameter val in the function definition to val1, and assigning the variables of the parent type to the variables of the child type, which is dangerous.

On the other hand, there is no problem with calling f (val2), because the type of val2 is a subtype of the val type, it has more properties, and it has all the properties that the function might use.

Suppose I'm going to develop a redux now, and when I declare a dispatch type, I can do this:

Interface Action {type: string} declare function dispatch (action: t)

In this way, it is constrained that the parameters passed in must be subtypes of Action. In other words, there must be type, and you can do whatever you want with other attributes.

Application in association type

After learning the above knowledge points, and then looking at the assignability of union types, it seems counterintuitive at first glance. Is'a'|'b'|'c'a subtype of'a'|'b'? Does it seem to have more attributes? On the contrary,'a'|'b'|'c'is the parent type of'a'|'b'. Because the former is more "broad" than the latter, and the latter is more "specific" than the former.

Type Parent ='a' |'b' |'c' type Son ='a' |'b' let parent: Parent let son: Son parent = son / / ✅ ok son = parent / / ❌ error! Parent could be'c'.

Here son can be safely assigned to parent because all the possibilities of son are covered by parent.

And vice versa, parent is too broad, it may be 'centering, this is the Son type hold can not live.

After reading this example, you should be able to understand why'a'|'b 'extends' a'|'b'|'c'is true, so you can use it more flexibly when writing conditional types.

Inverter and covariant

Let's start with the definition of Wikipedia [1]:

Covariant and inversion (Covariance and contravariance) is a term used in computer science to describe whether there is a parent / child type relationship between multiple types with a parent / child type relationship through the type constructor.

The description is rather obscure, but to explain the wave with our above example of animal types, we still have two father-son types, Animal and Dog.

Covariant (Covariance)

So imagine, now that we have these two subtypes of arrays, what should the father-son relationship be like? Yes, Animal [] is still the parent type of Dog [], and for such a piece of code, it is still safe to assign a child type to the parent type:

Let animals: Animal [] let dogs: Dog [] animals = dogs animals [0] .age / / ✅ ok

After converting to an array, for variables of the parent type, we still only go to those attributes that must be in the Dog type.

Then, for the type constructor type MakeArray= T [], it is Covariance.

Inverter (Contravariance)

There are two functions:

Let visitAnimal = (animal: Animal) = > void; let visitDog = (dog: Dog) = > void

Animal = dog is type safe, so visitAnimal = visitDog seems to be feasible? In fact, imagine the implementation of these two functions:

Let visitAnimal = (animal: Animal) = > {animal.age} let visitDog = (dog: Dog) = > {dog.age dog.bark ()}

Because the argument to visitDog expects a more specific subtype with the bark attribute, if visitAnimal = visitDog, we might pass it to visitDog with a normal animal type without the bark attribute.

VisitAnimal = visitDog let animal = {age: 5} visitAnimal (animal) / / ❌

This causes a run-time error, animal.bark does not exist, and calling this method can cause a crash.

But on the other hand, visitDog = visitAnimal is completely feasible. Because subsequent callers pass in a dog that is more specific than the animal attribute, all access within the function body is secure.

After calling the following type constructor on the Animal and Dog types, respectively:

Type MakeFunction = (arg: t) = > void

The parent-child type relationship is reversed, which is called Contravariance.

In TS

Of course, in TypeScript, the default handling of function parameters is bidirectional covariant due to trade-offs such as flexibility. That is, you can either visitAnimal = visitDog or visitDog = visitAnimal. Only when strictFunctionType in tsconfig is enabled will the assignment relationship be constrained strictly according to the inverter.

At this point, the study on "how to understand the subtypes, inverters and covariates in TypeScript" is over. I hope to be able to solve your doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report