好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

函数类型的子类型关系比较复杂,写SuperType和SubType可以理解(返回值类型的子类型关系)

1.首先

我曾经为理解子类型而苦苦挣扎,但我也为功能子类型而苦苦挣扎。

或者更确切地说,功能类型的亚型关系异常困难。
我写了一篇文章来表达我遇到的问题。

我们将分多个部分发布文章。

这一次,一个功能 按返回类型的子类型关系 是。

根据@uhyo 的“面向专业人士的 TypeScript 简介”进行学习。

如果您能指出我误解的地方,我将不胜感激。

2. 内容

1.首先
2. 内容
3.你可以从这篇文章中学到什么
4.环境
5. 功能亚型关系
  5.1. 什么是子类型关系?
  5.2. 什么是返回值类型的子类型关系?
  5.3. void类型的子类型关系
六,结论
7. 参考

3.你可以从这篇文章中学到什么

您可以通过函数类型的返回类型来查看子类型关系。

如果 S (SubType) 是 T (SuperType) 的子类型,
对于相同的参数列表
一个函数类型 (引数リスト) => S (SubType)变成一个子类型 (引数リスト) => T (SuperType)

您将能够理解此源代码。

  type   Engineer   =   { 
     name  :   string  ; 
     year  :   number  ; 
 }; 

 type   FrontendEngineer   =   { 
     name  :   string  ; 
     year  :   number  ; 
     frontendSkill  :   Array  <  string  >  ; 
 }; 

 const   hasFrontendSkill   =   (  frontendSkill  :   string  [])   =>   ({ 
     name  :   '  daishi  '  , 
     year  :   35  , 
     frontendSkill  , 
 }); 

 const   hasEngineerSkill  :   (  frontendSkill  :   string  [])   =>   Engineer   =   hasFrontendSkill  ; 

 const   daishiSkill  :   Engineer   =   hasEngineerSkill  ([  '  JavaScript  '  ,   '  TypeScript  '  ]); 

 console  .  log  (  daishiSkill  );   // { name: 'daishi', year: 35, frontendSkill: [ 'JavaScript', 'TypeScript' ] } 
 

4.环境

打字稿:4.7.4 Node.js:16.15.1

5. 功能亚型关系

5.1 什么是子类型关系?

在我进入功能子类型之前,我想先讨论一下子类型。

什么是子类型关系?
当需要一种类型的值 A 并且可以用另一种类型的值 B 替换时, B 被称为 A 的子类型。

A 是超类型, B 是子类型。

SuperType 的一部分是 SubType。
(这与面向对象的继承关系相同。)

如果你把它应用到上一句,我想你可以更具体地看到它。

B (SubType) 是 A (SuperType) 的子类型,当您需要一种类型的值时, A (SuperType) 可以用另一种类型的值替换 B (SubType) 表示。

怎么样,是不是比较容易想象亚型关系? (只有我一个人吗?)

在这篇文章中,我能够通过表达 SuperType 和 SubType 来理解类型之间的关系,所以
甚至这也被描述为 SuperType 和 SubType。

之前发过一篇关于子类型关系的文章,请参考。

5.2. 什么是返回值类型的子类型关系?

现在,我们来看看主体的函数类型的返回值类型的子类型关系。

当您有以下情况时,

S (SubType) 是 T (SuperType) 的子类型 函数具有相同的参数列表

函数类型的返回值成为子类型关系。

简而言之,
函数类型 (引数リスト) => S (SubType) 具有子类型关系 (引数リスト) => T (SuperType)。

在子类型关系的属性中
可以使用 S (SubType) 类型的值代替 T (SuperType) 类型的值。

通过将函数的返回类型的 S (SubType)类型值视为 T (SuperType)类型,

可以使用“返回 S (SubType)类型值的函数”代替“返回 T (SuperType)类型值的函数”。

比较混乱,还是看一下源码吧

  // SuperType の定義 
 type   Engineer   =   { 
     name  :   string  ; 
     year  :   number  ; 
 }; 

 // SubType の定義 
 type   FrontendEngineer   =   { 
     name  :   string  ; 
     year  :   number  ; 
     frontendSkill  :   Array  <  string  >  ; 
 }; 

 // SubType の関数 
 const   hasFrontendSkill   =   (  frontendSkill  :   string  [])   =>   ({ 
     name  :   '  daishi  '  , 
     year  :   35  , 
     frontendSkill  ,   // ← frontendSkill: frontendSkill を省略 
 }); 

 // SuperType の関数に SubType の関数を代入 
 const   hasEngineerSkill  :   (  frontendSkill  :   string  [])   =>   Engineer   =   hasFrontendSkill  ; 

 // SuperType の関数を呼び出し 変数 daishiSkill に代入 
 const   daishiSkill  :   Engineer   =   hasEngineerSkill  ([  '  JavaScript  '  ,   '  TypeScript  '  ]); 

 console  .  log  (  daishiSkill  );   // { name: 'daishi', year: 35, frontendSkill: [ 'JavaScript', 'TypeScript' ] } 
 

FrontendEngineer (SubType) 类型是 Engineer (SuperType) 类型的子类型。

如果你不知道它是什么意思,请参考我之前发布的关于部分类型的文章。

具有相同参数列表的函数 (frontendSkill: string[])
hasFrontendSkill (SubType) 是 hasEngineerSkill (SuperType) 的子类型。

简而言之,
(frontendSkill: string[]) => FrontendEngineer (子类型)是
它是 (frontendSkill: string[]) => Engineer (SuperType) 的子类型。

现在让我们仔细看看。

函数 hasFrontendSkill 的类型为 (frontendSkill: string[]) => FrontendEngineer 。

  const   hasFrontendSkill   =   (  frontendSkill  :   string  [])   =>   ({ 
     name  :   '  daishi  '  , 
     year  :   35  , 
     frontendSkill  ,   // ← frontendSkill: frontendSkill を省略 
 }); 
 

这被分配给 (frontendSkill: string[]) => Engineer (SuperType)类型的函数 hasEngineerSkill 。

  const   hasEngineerSkill  :   (  frontendSkill  :   string  [])   =>   Engineer   =   hasFrontendSkill  ; 
 

它使用参数 ['JavaScript', 'TypeScript'] 调用函数 hasEngineerSkill ,并将其分配给变量 daishiSkill 。
函数 hasEngineerSkill 是 Engineer 类型,所以变量 daishiSkill 也是 Engineer 类型。

  const   daishiSkill  :   Engineer   =   hasEngineerSkill  ([  '  JavaScript  '  ,   '  TypeScript  '  ]); 
 

即使变量 daishiSkill 的类型是 Engineer (SuperType) 类型,也会返回 frontendSkill: [ 'JavaScript', 'TypeScript' ] 。

  console  .  log  (  daishiSkill  );   // { name: 'daishi', year: 35, frontendSkill: [ 'JavaScript', 'TypeScript' ] } 
 

“ Engineer 的类型定义中没有定义 frontendSkill 属性??”
你可能想知道,

这是,
hasEngineerSkill 是 Engineer 类型(SuperType)的函数, hasFrontendSkill 是不同于 FrontendEngineer 类型(SubType)类型的函数,
hasFrontendSkill (SuperType)赋值给 hasEngineerSkill (SubType),所以内容是同一个函数对象。

  const   hasEngineerSkill  :   (  frontendSkill  :   string  [])   =>   Engineer   =   hasFrontendSkill  ; 
 

所以调用任何一个都会给出相同的结果。

所以即使你用 hasEngineerSkill(['JavaScript', 'TypeScript']) 调用函数
变量 daishiSkill 包含一个具有 Engineer 和 FrontendEngineer 类型属性的对象。

像这种子类型关系,可以得到比变量中定义的类型信息 Engineer 更多的对象。

这是一个子类型关系容易混淆的概念......
我很困惑。

我觉得如果我能掌握SuperType和SubType哪个函数(个人印象)会更容易理解。

5.3. void类型的子类型关系

我希望你通过返回类型来理解子类型的关系,但是 void 类型有一个特殊的行为

返回任何类型的函数类型 (SubType) 被视为采用相同参数并返回类型 void 的函数类型 (SuperType) 的子类型。

让我们看看发生了什么。

由于 void 类型没有返回值,
可以使用任何返回任何值(SubType)的函数来代替不返回任何值的函数(SuperType)。

  // SubType 
 const   f   =   (  name  :   string  )   =>   ({   name   }); 

 // SuperType 
 const   g  :   (  name  :   string  )   =>   void   =   f  ; 
 

函数 f 是 (name: string) => { name: string; } 类型的函数(SubType),
它可以分配给 (name: string) => void 类型函数 g (SuperType)。

我写的是特殊的,但是和前面通过返回值类型的子类型关系是一样的道理。

六,结论

这有点令人困惑......

一开始我完全不明白。
我花了几个小时才明白...

如果将 SuperType 和 SubType 应用于函数的返回值类型,可以看到子类型关系。

下次会更复杂 按参数类型的子类型关系 我会看看。

如果您也可以阅读其他文章,我会很高兴?‍♂️

7. 参考

书:面向有抱负的专业人士的 TypeScript 简介 Ryota Suzuki [作者]


原创声明:本文系作者授权爱码网发表,未经许可,不得转载;

原文地址:https://www.likecs.com/show-308626943.html

查看更多关于函数类型的子类型关系比较复杂,写SuperType和SubType可以理解(返回值类型的子类型关系)的详细内容...

  阅读:58次