Type Script真香シリーズ-タイプ推論とタイプ互換性


前言
Type Script真香シリーズの内容は中国語の文書を参照しますが、文書の例とほとんど重複しません.一部のところについても深く研究しています.また、いくつかの例の結果は、コードに誤りがない後、JavaScriptにコンパイルされたものです.実際にType Scriptを見たいなら、JavaScriptとしてコンパイルされたコードは、Type Scriptのオンラインアドレスにアクセスして、操作して、より印象的です.
類型推論
基礎
Type Scriptのタイプ推論は、変数のタイプを明確に指定していない場合、Type Scriptは変数のデータタイプを自動的に推定することができます.
let a = 3;
a = 4;
a = "s";  //  ,"s" number     
上記の例から、変数aを定義した後、値を賦課すると、Type Scriptは変数aの種類を自動的に推定してくれることが分かります.変数aに文字列を割り当てると、コードのエラーメッセージが表示されます.このような書き方はJavaScriptでは可能ですが、Type Scriptでは制限されています.
let a = {
    p: "",
    c: 0
};
a.p = "  ";
a.p = 1; //  ,1 string     
最適共通タイプ
上記の例は簡単ですが、私達が定義した変数が配列という比較的複雑なタイプの場合、Type Scriptはその中のメンバーによって最適な汎用タイプを推定します.
let a = [1, 2, null];
a=["s"];  //  ,  "string" "number | null"   
コンテキストのタイプ
上記の例は右から左にかけて判定されるタイプです.Type Scriptタイプの推論も逆の方向から推測されることがあります.これは「コンテキスト分類」と呼ばれ、文脈分類によって表現の種類と位置が関係する場合があります.以下の例は関数のセクションにあります.
function sum(a: number, b: number){
    return a + b;
}
戻り値のタイプは指定されていませんが、Type Scriptは自動的に上から下まで推定されます.
number。
let man = {
    a: 1,
    b: "james",
    play: (s: string) => {
        return s
    }
}

man.play = function (s){ 
   return s + "s"
}
タイプ互換性
基礎
Type Scriptのタイプの互換性は、他のタイプに与えられるかどうかを判定するために使用されてもよい.ここで二つの概念を理解します.
構造タイプ:1つはそのメンバーだけを使用してタイプを記述する方法.
名義のタイプ:はっきりと指摘したり、宣言したりするタイプ、例えばc葃、java.
Type Scriptのタイプ互換性は構造のサブタイプに基づいています.以下の例:
interface IName {
    name: string;
}

class Man {
    name: string;
    constructor() {
        this.name = "  ";
    }
}

let p: IName;
p = new Man();
p.name;
上のコードはType Scriptで間違いないですが、javaなどの言語でエラーが発生します.Man類は明確な説明がないので、INameインターフェースを実現しました.上の例は何も反映されていないと感じる人がいるかもしれませんが、次のような互換性のない例を見ます.
let man: string = "  ";
let age: number = 20;

man = age;  //   ,  number   string   
age = man;  //   ,  string   number   
互換性のある例を見てください.
let man: any = "  ";
let age: any = 123
man = age;  //123
構造化
Type Script構造型システムの基本的なルールは、xがyに互換性があるなら、yは少なくともxと同じ属性を持つ.次の例のように:
interface IName { 
    name: string;
}
let x: IName;
let y = {name: "  ", age: 123, hero: true};
x = y;  //{name: "  ", age: 123, hero: true}
ここでコンパイラはxの各属性をチェックします.yにも対応する属性が見つけられますか?上のyはx互換性の要求に適合しています.即ちx互換yです.
interface IName { 
    name: string;
    age: number
}
let x: IName;

let z = { name: "  ", cool: true };
x = z; //   
ここでコンパイラがチェックすると、zにはxの「age」という属性がないことが分かりますので、xとzは互換性がありません.
比較関数
パラメータが違います
上記の例はいくつかのオリジナルのタイプまたはオブジェクトの比較です.関数間の比較を見てみます.
let x = (a: number) => 0;
let y = (b: number, c: string) => 0;

y = x; 
x = y; //  
xがyに割り当てられるかどうかを見るには、xとyのパラメータリストを先に見ます.xの各パラメータはyの中に対応するタイプのパラメータを見つけなければなりません.パラメータの種類が対応していれば、パラメータの名前は構いません.上記の例ではxのパラメータはyに対応するパラメータを見つけることができますので、値の割り当ては許可されますが、逆にyはxに値を付けることができません.
関数パラメータの双方向共変
双方向協働は協働とインバータを含む.協働とはサブタイプの互換性のある親タイプのことで、インバータは正反対です.
let man = (arg: string | number) : void => {};
let player = (arg: string) : void => {};

man = player;
player = man;
オプションとレスポンスパラメータ
オプションパラメータとレスポンスパラメータの互換性については、以下の例を参照してください.
let man = (x: number, y: number) => {};
let work = (x?: number, y?: number) => {};
let play = (...args: number[]) => {};

man = work = play;
play = work = man;
関数の再ロード
リロードについては、まずjavaの定義を見てみます.同じクラスでは、同じ名前の関数が一つ以上存在することができます.彼らのパラメータの数やパラメータの種類が違っていればいいです.戻り値タイプに関係なく、パラメータリスト(パラメータの個数、パラメータの種類、パラメータの順序)のみを見ます.
Type Scriptにおける関数の再負荷とjavaにおける違いは、Type Scriptにおける関数の負荷はパラメータタイプのみです.
function sum(a: number, b: number): number;
function sum(a: string, b: string): string;

function sum(a: any, b: any) {
    let result = null;
    if (typeof a === "string" && typeof b === "string") {
        result = a + " " + b + "    ";
    } else if (typeof a === "number" && typeof b === "number") {
        result = a + b
    }
    return result;
}
sum("  ", "  ");
sum(1, 1);
リロードされた関数の場合、ソース関数の各リロードはターゲット関数に対応する関数署名を見つけます.以下のような方法はエラーです.
function sum(a: number, b: number): number; //   ,             
function sum(a: string, b: string): string{
    return a + b;
};
以下の例はType Scriptでも再負荷できません.
function sum(a: number, b: number): number{ //  ,      
    return a + b;
};
function sum(a: any, b: any): any{ //  ,      
    return a + b;
};
戻り値が違います
次に、戻り値の種類をどう比較するかを見ます.ソース関数の戻りのタイプは、ターゲット関数の戻り値のサブタイプでなければなりません.
interface IMan {
  x: string;
  y: number;
}
interface IPlayer {
  x: string;
  y: number;
  z: number;
}
 
let man = (): IMan => ({ x: "  ", y: 0 });
let player = (): IPlayer => ({ x: "  ", y: 0, z: 0 });
 
man = player;
player = man; //  
上からわかるように、playerはmanのサブタイプなので、man互換playerです.以下の例もこの点を示している.
interface IMan {
  x: string;
  y: number;
}
interface IPlayer {
  a: string;
  b: number;
  c: number;
}
 
let man = (): IMan => ({ x: "  ", y: 0 });
let player = (): IPlayer => ({ a: "  ", b: 0, c: 0 });
 
man = player; //  
player = man; //  
列挙
列挙のタイプと数字のタイプは互換性があります.
enum Man {
    name,
    age,
}

let num = 1;
let num2 = 2;
let enumNum: Man.name = num; 
num2 = Man.name;
異なる列挙の間は互換性がない:
enum Man {
    name,
    age,
}

enum Player { 
    name,
    age,
}
let man: Man.name = Player.name; //  ,  Player.name        Man.name
let player: Player.age = Man.age;  //  ,   Man.name        Player.name
クラス
クラスの基本比較
Type Scriptでは、例示的なメンバーと方法だけが比較され、静的なメンバーと構造関数は比較されない.
class Man {
    name: string;
    constructor(arg: string,) {
        this.name = arg;
    }
    showName() {
        return this.name;
    }
}

class Player {
    static age: number;
    name: string;
    constructor(arg: string, hero: boolean) {
        this.name = arg;
    }
    showName() {
        return this.name;
    }
}

let man = new Man("  ");
let player = new Player("  ", true);

man = player;
player = man;
上記の例から、2つのクラスは異なる構造関数と静的構成員を持っているが、彼らは同じ実例的な構成員と方法を持っているので、彼らの間に互換性があることが分かる.
クラスのプライベートメンバーと保護されたメンバー
クラスのプライベートメンバーと保護されたメンバーの互換性の比較規則は同じです.二つの種類を比較する時、二つの種類に分けて見ます.二つの種類は親子で、父類に私有メンバーがいる場合、二つの種類は互換性があります.2つのクラスが同じクラスのクラスであり、また、同じクラスにプライベートまたは保護されたメンバーが含まれている場合は、互換性がありません.次の二つの例を見てください.親子類:
class Man {
    private name: string;
    
    constructor(arg: string) {
        this.name = arg;
    }
    
}

class Player extends Man {
    
    constructor(arg: string) {
        super(arg);
    }
    
}

let man = new Man("  ");
let player = new Player("  ");
//Man  Player     ,         
man = player;
player = man;
クラス:
class Man {
    private name: string;
    constructor(arg: string) {
        this.name = arg;
    }
    
}

class Player {
    private name: string;
    constructor(arg: string) {
       this.name = arg;
    }
    
}

let man = new Man("  ");
let player = new Player("  ");

man = player; //   ,  Player       Man,        name     
player = man; //   ,  Man       Player,        name     
汎型
Type Script汎型の互換性は二つの場合に分けられます.一つはタイプパラメータがメンバーに使用されていません.もう一つは、タイプパラメータがメンバーによって使用されることである.まずタイプパラメータがメンバーに使用されていない場合を見ます.
interface IMan{

}

let man1: IMan;
let man2: IMan;
man1 = man2;
man2 = man1;
タイプパラメータがメンバーによって使用される場合:
interface IMan{
    name: T;
}

let man1: IMan;
let man2: IMan;
man1 = man2;  //  ,IMan     IMan
man2 = man1;  //  ,IMan     IMan


interface IMan{
    name: T;
}

let man1: IMan;
let man2: IMan;
man1 = man2;  
man2 = man1;
Type Scriptの汎型では、タイプパラメータがメンバーに使用されていない場合、互換性には影響がありません.パラメータがメンバーによって使用されると、互換性に影響します.
参照
https://github.com/zhongsp/Ty... https://github.com/jkchao/typ...
最後に
文章の中には自分の理解を入れるところがあります.正確でないところや間違っているところがあれば、ご指摘ください.