1.首先
上次发了一篇关于函数类型的返回值类型的子类型关系的文章。
作为续集,这一次 函数类型参数类型的子类型关系 我写了一篇文章
它太复杂了,我担心我是否能够正确地用语言表达它......
如果您能指出我误解的地方,我将不胜感激。
这一次,我根据@uhyo 的“面向专业人士的 TypeScript 简介”赶上了。
不,这真的很混乱。
2. 内容
1.首先
2. 内容
3.你可以从这篇文章中学到什么
4.环境
5. 函数类型参数类型的子类型关系
5.1. 什么是参数类型的子类型关系?
5.2. 尝试按参数类型使用子类型关系
5.3. 具有多个参数类型的子类型关系
5.4. 多个参数同时子类型化时的函数类型
5.5.按参数的子类型关系和按返回值类型的子类型关系的组合
六,结论
7. 参考
3.你可以从这篇文章中学到什么
以下 函数类型参数类型的子类型关系 可以了解一下
“以 SuperType 类型作为参数的函数”成为“以 SubType 类型作为参数的函数”的子类型
// SuperType のオブジェクトの定義 type Engineer = { name : string ; year : number ; }; // SubType のオブジェクトの定義 type FrontendEngineer = { name : string ; year : number ; frontendSkill : Array < string > ; }; // SuperType の型を引数にもった SubType の型の関数 const frontendEngineerInfo = ( engineer : Engineer ): FrontendEngineer => { return { frontendSkill : [ '' ], ... engineer , }; }; // engineerInfo 関数を SubType の型を引数に持った SuperType の型に代入 const engineerInfo : ( frontendEngineer : FrontendEngineer ) => Engineer = frontendEngineerInfo ; // 関数 engineerInfo を使用する const info = engineerInfo ({ name : ' daishi ' , year : 1 , frontendSkill : [ ' JavaScript ' ], }); console . log ( info ); // { frontendSkill: [ 'JavaScript' ], name: 'daishi', year: 1 }
4.环境
打字稿:4.7.4 Node.js:16.15.15.函数类型参数类型的子类型关系
看这篇文章之前,请先阅读【TypeScript】函数类型的子类型关系比较复杂,写完SuperType和SubType(返回值类型的子类型关系)我觉得后面理解起来比较容易。
现在让我们看看具有不同参数类型的函数类型之间的子类型。
5.1. 什么是参数类型的子类型关系?
当 S 类型(SubType)是 T 类型(SuperType)的子类型时,
“接收类型(SuperType)作为参数的 T 函数”(SubType)的类型是“接收类型(SubType)作为参数的 S 函数”(SuperType)的子类型。
参考:面向专业人士的 TypeScript 简介(SuperType、SubType 添加)
子类型关系的方向颠倒了……
(这很混乱……)
(我希望我能在我的评论中理解这一点)
我的印象已经进入,但我会继续......
我觉得如果你根据子类型的原理来思考会更容易理解:“ S 类型(SubType)的值代替了 T 类型(SuperType)的值。”
这是因为即使在需要 T 类型(SuperType)参数的地方接收到 S 类型(SubType)值,它也可以被视为 T 类型(SuperType)值。
简而言之,
接收 T 类型(SuperType)作为参数的函数可以被视为接收 S 类型(SubType)作为参数的函数。
这是,
“接收 T 类型(SuperType)作为参数的函数”(SubType)是“接收 S 类型(SubType)作为参数的函数”(SuperType)的子类型。
参考:面向专业人士的 TypeScript 简介(SuperType、SubType 添加)
这很混乱,但它是这样的 w
这是一种面向对象的继承关系。
让我们仔细看看。
5.2. 尝试按参数类型使用子类型关系
以下源代码是取决于参数类型的部分类型关系。
// SuperType のオブジェクトの定義 type Engineer = { name : string ; year : number ; }; // SubType のオブジェクトの定義 type FrontendEngineer = { name : string ; year : number ; frontendSkill : Array < string > ; }; // SuperType の型を引数にもった void 型の関数 const engineerInfo = ( engineer : Engineer ) => { console . log ( engineer . name ); console . log ( engineer . year ); }; // engineerInfo 関数を引数に SubType の型をもった関数に代入 const frontendEngineerInfo : ( frontendEngineer : FrontendEngineer ) => void = engineerInfo ; // 関数を使用する frontendEngineerInfo ({ name : ' daishi ' , year : 1 , frontendSkill : [ ' JavaScript ' ], }); // 実行結果 // daishi // 1
如果将前面按参数类型的子类型关系中描述的内容应用到本次的内容上,
“接收 Engineer 类型(SuperType)作为参数的函数”(SubType)是“接收 FrontendEngineer 类型(SubType)作为参数的函数”(SuperType)的子类型。
让我们将其重写为功能描述。
(engineer: Engineer) => void 类型(SubType)是 (frontendEngineer: FrontendEngineer) => void 类型(SuperType)的子类型
变成。
现在让我们看看为什么会发生这种情况。
首先,作为先决条件,
FrontendEngineer 类型 (SubType) 是 Engineer 类型 (SuperType) 的子类型。
@ 987654342 @
子类型关系原则
当 S 类型(SubType)是 T 类型(SuperType)的子类型时, “ S (SubType) 类型的值替换 T (SuperType) 类型的值” 这就是为什么,
可以使用 FrontendEngineer (SubType)类型的值代替 Engineer (SuperType)类型的值。
Engineer Engineer 类型 (SuperType) 参数接收 FrontendEngineer 类型 (SubType) 参数,但它们可以用作 Engineer 类型 (SuperType) 参数。
简而言之,
可以使用“ Engineer 接收类型(SuperType)作为参数的函数”代替“ FrontendEngineer 接收类型(SubType)作为参数的函数”。
这意味着
“接收 Engineer 类型(SuperType)作为参数的函数”(SubType)是“接收 FrontendEngineer 类型(SubType)作为参数的函数”(SuperType)的子类型。
现在您可以看到参数和返回类型是相反的。
这就是为什么,
(engineer: Engineer) => void 类型函数(SubType)可以被视为 (frontendEngineer: FrontendEngineer) => void 类型函数(SuperType)。
有点乱,不过我想你一个一个看就明白了。
(一一看还是一头雾水……)
现在让我们回到源代码。
// SuperType の型を引数にもった void 型の関数 const engineerInfo = ( engineer : Engineer ) => { console . log ( engineer . name ); console . log ( engineer . year ); }; // engineerInfo 関数を引数に SubType の型をもった関数に代入 const frontendEngineerInfo : ( frontendEngineer : FrontendEngineer ) => void = engineerInfo ;
frontendEngineerInfo 函数接收 FrontendEngineer 类型(子类型)的参数。
但是,由于 FrontendEngineer 类型(SubType)是 Engineer 类型(SuperType)的子类型,
该函数有效,因为 FrontendEngineer 类型(SubType)也可以被视为 Engineer 类型(SuperType)。
因此,具有 (engineer: Engineer) => void 类型(SubType)的函数 engineerInfo 是
可以将其视为 (frontendEngineer: FrontendEngineer) => void 类型(SuperType)的 frontendEngineerInfo 函数。
您可以将功能 engineerInfo 分配给 frontendEngineerInfo 。
现在调用函数 frontendEngineerInfo 。
// 関数を使用する frontendEngineerInfo ({ name : ' daishi ' , year : 1 , frontendSkill : [ ' JavaScript ' ], });
由于函数 engineerInfo 可以被视为 frontendEngineerInfo ,
// SuperType の型を引数にもった void 型の関数 const engineerInfo = ( engineer : Engineer ) => { console . log ( engineer . name ); console . log ( engineer . year ); };
在函数 engineerInfo (SubType) 的参数中
{ name: 'daishi', year: 1, frontendSkill: ['JavaScript', 'TypeScript'] } 已通过
engineer.name 和 engineer.year 是输出,所以 daishi 和 1 是输出。
这里,
“为什么 Engineer 类型只有 name 和 year 属性?
您是否传递了额外的 frontendSkill: Array<string> ? ”
你可能会有疑问。
// SuperType のオブジェクトの定義 type Engineer = { name : string ; year : number ; };
但是,即使函数 engineerInfo 的参数 engineer 有额外的属性,也不影响操作。
可能会让人感到困惑,因为类型和参数是混合的,
使用功能时 未使用的值 即使您传递包含作为参数的对象或数组也没有问题。
这是一样的。
以上是参数类型的子类型关系。
这有点复杂,但如果您记住您使用的是 SubType 而不是 SuperType,您应该能够掌握它的窍门。
接下来,我们看一下当有多个参数时,根据参数类型的子类型关系。
5.3. 具有多个参数类型的子类型关系
即使有多个参数,参数类型的子类型关系也是相同的。
这次,
第一个参数是子类型关系 第二个参数相同让我们看看有两个参数的情况。
这是一个子类型关系。
// SuperType のオブジェクトの定義 type Engineer = { name : string ; year : number ; }; // SubType のオブジェクトの定義 type FrontendEngineer = { name : string ; year : number ; frontendSkill : Array < string > ; }; // SuperType の型と boolean 型を引数にもった void 型の関数 const engineerInfo = ( engineer : Engineer , isPM : boolean ) => { console . log ( engineer . name ); console . log ( engineer . year ); console . log ( isPM ); }; // engineerInfo 関数を SubType の型と boolean 型を引数にもった関数に代入 const frontendEngineerInfo : ( frontendEngineer : FrontendEngineer , isPM : boolean ) => void = engineerInfo ; // 関数 rontendEngineerInfo を使用する frontendEngineerInfo ( { name : ' daishi ' , year : 1 , frontendSkill : [ ' JavaScript ' ], }, false , ); // 実行結果 // daishi // 1 // false
(engineer: Engineer, isPM: boolean) => void 类型(SubType)函数 engineerInfo 是
(frontendEngineer: FrontendEngineer, isPM: boolean) => void 成为类型 (SuperType) 的函数 frontendEngineerInfo 的子类型。
这是, 尝试按参数类型使用子类型关系 同样的道理。
函数 frontendEngineerInfo
第一个参数 frontendEngineer 即使接收到 FrontendEngineer 类型(SubType)的值,也可以认为是 Engineer 类型(SuperType) 由于第二个参数相同,所以可以按原样使用因此,您可以将函数 engineerInfo 视为函数 frontendEngineerInfo 的替代品。
5.4. 多个参数同时子类型化时的函数类型
当多个参数同时处于子类型关系中时,函数类型中也会出现子类型关系。
第一个参数是子类型关系 第二个参数的相同子类型关系是一个参数为的函数
让我们看一下源代码。
// SuperType のオブジェクトの定義 type Engineer = { name : string ; year : number ; }; // SubType のオブジェクトの定義 type FrontendEngineer = { name : string ; year : number ; frontendSkill : Array < string > ; }; // 複数の SuperType の型の引数をもった void 型の関数 const engineerInfo = ( kakedashiEngineer : Engineer , seniorEngineer : Engineer ) => { console . log ( kakedashiEngineer . name ); console . log ( kakedashiEngineer . year ); console . log ( seniorEngineer . name ); console . log ( seniorEngineer . year ); }; // engineerInfo 関数を 複数の SubType の型を引数にもった関数に代入 const frontendEngineerInfo : ( kakedashiFrontendEngineer : FrontendEngineer , seniorFrontendEngineer : FrontendEngineer ) => void = engineerInfo ; // 関数 frontendEngineerInfo を使用する frontendEngineerInfo ( { name : ' daishi ' , year : 1 , frontendSkill : [ ' JavaScript ' ], }, { name : ' manju ' , year : 10 , frontendSkill : [ ' JavaScript ' , ' TypeScript ' ], }, ); // 実行結果 // daishi // 1 // manju // 10
(kakedashiEngineer: Engineer, seniorEngineer: Engineer) => void 类型(SubType)函数 engineerInfo 是 (kakedashiFrontendEngineer: FrontendEngineer, seniorFrontendEngineer: FrontendEngineer) => void 类型(SuperType)函数 frontendEngineerInfo 的子类型。
推理完全一样,所以省略说明。
当多个亚型关系共存时,它们必须具有相同的方向才能导致功能性亚型关系。
如果有 (engineer: Engineer, frontendEngineer: FrontendEngineer) => void 和 (frontendEngineer: FrontendEngineer, engineer: Engineer) => void 类型,
这不是子类型关系。
这是因为第一个参数和第二个参数的子类型关系的方向是相反的,当两者结合时无法分辨哪个是哪个SuperType。
5.5.按参数的子类型关系和按返回值类型的子类型关系的组合
按参数进行子类型化可以与按返回类型进行子类型化结合使用。
// SuperType のオブジェクトの定義 type Engineer = { name : string ; year : number ; }; // SubType のオブジェクトの定義 type FrontendEngineer = { name : string ; year : number ; frontendSkill : Array < string > ; }; // SuperType の型を引数にもった SubType の型の関数 const frontendEngineerInfo = ( engineer : Engineer ): FrontendEngineer => { return { frontendSkill : [ '' ], ... engineer , }; }; // engineerInfo 関数を SubType の型を引数に持った SuperType の型に代入 const engineerInfo : ( frontendEngineer : FrontendEngineer ) => Engineer = frontendEngineerInfo ; // 関数 engineerInfo を使用する const info = engineerInfo ({ name : ' daishi ' , year : 1 , frontendSkill : [ ' JavaScript ' ], }); console . log ( info ); // { frontendSkill: [ 'JavaScript' ], name: 'daishi', year: 1 }
(engineer: Engineer) => FrontendEngineer 类型 (SubType) 是 (frontendEngineer: FrontendEngineer) => Engineer 类型 (SuperType) 的子类型。
看起来很复杂,因为返回类型是反转的,但是逻辑和之前一样。
但这很令人困惑...
六,结论
这很令人困惑,因为参数类型和返回值类型是相反的......
重要的, SubType 值替代 SuperType 值 是。
我认为您可以通过逐个检查哪种类型是哪种类型的子类型来查看流程。
在我习惯它之前,我想在查看关系的同时跟随源代码,好像在施法说“SubType值替换SuperType值”。
我在发秀一,如果你也能看其他文章我会很高兴?♂️
7. 参考
书:面向有抱负的专业人士的 TypeScript 简介 Ryota Suzuki [作者]
原创声明:本文系作者授权爱码网发表,未经许可,不得转载;
原文地址:https://www.likecs.com/show-308628181.html
查看更多关于函数类型的参数类型依赖的子类型关系是不是太复杂了?所以我试着尽可能地咀嚼它。的详细内容...