TS compatibility

This chapter is part of the notes of learning TS by yourself, watching the videos on the official website and finding information

This TS compatibility check looks a little bit on the website, but is actually quite difficult to understand

For the record, this is a collection of TS compatibility

If you want to see TS function compatibility, you can skip to the section on function compatibility

To read on, first understand what TS compatibility is?

The principle of compatibility is duck-check, i.e

The type check will pass if an attribute in the type of the variable being assigned exists in the type of the source being assigned

Interface compatibility

If the variable type passed by a function does not match the declared type, TS checks for compatibility

interface Animal {
    name: string;
    age: number;
}

interface Person {
    name: string;
    age: number;
    gender: number
}
// Determine if the target type 'Person' is compatible with the input source type 'Animal'
function getName(animal: Animal) :string {
    return animal.name;
}

let p = {
    name: 'lzy'.age: 25.gender: 0
}

getName(p);
// Only when the parameter is passed will the two variables be compared for compatibility.
// The assignment does not compare, and an error is reported directly
let a: Animal = {
    name: 'lzy'.age: 25.gender: 0 / / an error
}
Copy the code

In the third article, TS Interface,

Object literals undergo additional property checking when taken directly as arguments

If you write it as an object and pass it as a parameter to a function call, you don’t check for extra properties on the object,

Obviously, calling a function passes in an object literal directly, which is equivalent to assigning a parameter (to a variable) directly, while

No compatibility check is performed on variable assignments. Additional attributes are not allowed.

Function calls passing parameters are tolerated in the case of passing a variable whose value is an object, allowing compatibility

Function calls with extra property literals assigned to the object as arguments, and passed in as arguments.

This is because THE TS considers that variable checks have already been done when the object is assigned, so it is safe to allow compatibility.

Base type compatibility

// Basic data types are also compatible
let num : string|number;
let str:string='zhufeng';
num = str;

String variables can be assigned as long as the toString() method is present
let num2 : {
  toString():string
}

let str2:string='jiagou';
num2 = str2;
Copy the code

Class compatibility

When comparing the class types of two variables, only the instance members are compared

Private and protected members of a class affect compatibility. When checking the compatibility of class instances, if the target type contains a private member, the source type must contain that private member from the same class. Similarly, this rule applies to type checking that contains instances of protected members. This allows subclasses to assign to their parents, but not to other classes of the same type.

class Animal {
  feet: number;
  // If name is preceded by public, then a = s is an error because modifiers are added to the instance
  constructor(name: string,numFeet: number){}}class Size {
  feet: number;
  // If numFeet and numFeet are set to public, the two equations are still valid
  // If numFeet and numFeet are private, both equations are wrong
  constructor(numFeet: number){}}let a: Animal;
let s: Size;

a = s;  // OK
s = a;  // OK
Copy the code

When comparing instance parts of a class, only the structure of the instance part is compared, regardless of the type name

class Animal{ name:string }
class Bird extends Animal{ swing:number }

let a:Animal = new Bird();

// Not Java's 'parent compatible subclass, but subclass incompatible parent class'
// Just because bird needs an attribute swing:number, new Animal() not available
let b:Bird = new Animal(); / / an error
Copy the code

The following example shows that it doesn’t matter whether the type is a subclass parent, as long as the structure matches

class Animal{ name:string }
// If the parent class has the same structure as the subclass, this works fine
class Bird extends Animal{}

let a:Animal = new Bird();

let b:Bird = new Animal();
// Two completely unrelated classes can also be assigned to each other, as long as the structure matches
Copy the code

Function compatibility

A function assigns a value to a variable by comparing its arguments and then its return value

type sumFunc = (a:number,b:number) = >number;
let sum:sumFunc;
function f1(a:number,b:number) :number{
  return a+b;
}
// You can omit an argument
function f2(a:number) :number{
   return a;
}
sum = f2;
// Two arguments can be omitted
function f3() :number{
    return 0;
}
 // Add one more parameter
function f4(a:number,b:number,c:number){
    return a+b+c;
}
sum = f1;
sum = f2;
sum = f3;
sum = f4; / / an error

// An object that returns a value can have more attributes than the variable requires
Copy the code

The function that assigns a value to a variable requires fewer arguments than the function that assigns a value to a variable requires more arguments than the function that assigns a value to a variable

Parent-class compatibility of function plus argument types

When assigning a function to a variable whose type is defined

A function assigned to a variable

Arguments can have fewer attributes than those required in the variable type definition (contravariant)

The return value can be more than the required attribute in the variable type definition (covariant)

Simplified version:

Function parameters that assign values to variables can have fewer attributes and return values can have more attributes.

To understand:

The parameters of the function used for assignment must have fewer attributes than the variable being assigned

The return value of the function used to assign must have more properties than the variable to which it is assigned.

In practice, in type checking, only the type of the variable is checked, not the type of the value to which the variable is assigned (since values are mutable, the point is that the value has already been checked when the variable is assigned).

If the return value of the function used for assignment is not required to have an attribute equal to or greater

Later use of the variable will occur,

When type checking, it is allowed to use an attribute of the return value (because the variable type constraint says yes),

The return value of this attribute is undefined(because the real function value of the variable returns less value than the constraint value of the variable class).

An execution error occurs.

If you do not require that the parameters of the function used for assignment have attributes equal to or less

This occurs when the variable is later used

When checking the type of A variable, it is allowed to use the variable A to call the variable.

When the compiler executes, it is found that variable A is missing an attribute (because the real function value of A variable requires more parameter attributes than the variable type constraint).

An execution error occurs

class Animal{}
class Dog extends Animal{
    public name:string = 'Dog'
}
class BlackDog extends Dog {
    public age: number = 10
}
class WhiteDog extends Dog {
    public home: string = 'Beijing'
}
let animal: Animal;
let blackDog: BlackDog;
let whiteDog: WhiteDog;
// Error: the dog parameter is incompatible with the blackDog parameter.
// blackDog argument qualified functions require age attributes. Dog argument qualified variables are not mandatory.
// Assume no error here
// The call function can be of type dog through the childToChild variable
// The function value requires the age attribute of type blackDog
const childToChild: (dog: Dog) = >Dog = (blackDog: BlackDog): BlackDog= > {
  // The return value is changed to blackDog with more attributes.
  return new BlackDog()
}

// Error: the dog parameter is incompatible with the blackDog parameter. BlackDog requires age, but dog does not.
const childToParent: (dog: Dog) = >Dog = (BlackDog: BlackDog): Animal= > {
  // Error: The return value is changed to blackDog, which has fewer attributes.
  return new Animal()
}

// The argument is an aniamal that requires fewer attributes
const parentToParent: (dog: Dog) = >Dog = (animal: Animal): Animal= > {
  // Error: the return value cannot be of the animal type with fewer attributes, only of the animal class with more attributes
  return new Animal()
}

// Completely OK, the type attribute of the function parameter used for assignment requires fewer type attributes and more type attributes of the return value parameter
const parentToChild: (dog: Dog) = >Dog = (animal: Animal): BlackDog= > {
  return new BlackDog()
}
//(Animal → Greyhound) ≼ (Dog → Dog)
Copy the code

Compatibility with generics

To be clear, an interface is a type and a type, and a generic type needs to be converted to a specific type

Rule: Determine the specific type of the incoming generic T, and then determine compatibility

//1. The interface content is empty or as useless as the generic or passed T
// or T of y is equal if it is a subclass of T of x
interface Empty<T>{
    name:string
}
letx! :Empty<string>;
lety! :Empty<number>;
x = y;

//2. Interface contents are not equal when they are not empty
interface NotEmpty<T>{
  data:T
}
letx1! :NotEmpty<string>; / /! Not empty assertion
lety1! :NotEmpty<number>;
x1 = y1; / / an error

// Demo2 is equivalent to the following
interface NotEmptyString{
    data:string
}

interface NotEmptyNumber{
    data:number
}
letxx2! :NotEmptyString;letyy2! :NotEmptyNumber; xx2 = yy2;/ / an error
Copy the code

If it is a generic type with no specified type, T is treated as any

let identity = function<T> (x: T) :T {}let reverse = function<U> (y: U) :U { }

identity = reverse;  // OK, because (x: any) => any matches (y: any) => any
Copy the code

Enumeration compatibility

Enumeration types are compatible with numeric types

Different enumeration types are incompatible

// Numbers can be assigned to enumerations
enum Colors {Red=1,Yellow=2}
enum Colors2 {Red=1,Yellow=2}
let c:Colors;
let c2:Colors2;
c = Colors.Red;
c = 1;
c = '1'; / / an error
c = Colors2.Red / / an error

// Enumeration values can be assigned to numbers
let n:number;
n = 1;
n = Colors.Red;
Copy the code

The last

Rookie understand, there may be some mistakes, the big guy mercy, at the same time thanks for your advice.

Humbly recommend a wave of personal website Luo Ziyu’s blog, although in fact there is nothing