由于 typescript 越来越复杂. 所以特意开多一个篇幅来记入一些比较难的, 和一些到了一定程度需要知道的基础.

主要参考

https://basarat.gitbook.io/typescript/ 高级书

https://jkchao.github.io/typescript-book-chinese/ 高级书中文版

版本 feature

字节前端的 typescript (它掘金几篇都写的不错)

字节前端的 typescript (它掘金几篇都写的不错)

1. 名词术语

Basic Annotation 是基本注解 let a : string

Inline Type Annotation 是内联类型注解 let a : { name: string }

Union 是联合类型 string | number

intersection 是交叉类型 string & number

Tuple 是 元组类型[string, number]

Nullish Coalescing 是 ??

Optional Chaining 是可选链 obj?.name

Rest parameter 是  call(...args : string[])

Spread operator 是 call(...['a', 'b'])

Conditional 是 T extends string ? number : never;

Type Guard 是 类型保护 arg is Foo

Destructuring 是解构 const { name } = { name: 'Derrick' }

Naked type 是 type Naked<T> = T extends ... (没有被任何东西包装)

NotNaked type 是 type NotNaked<T> = { o: T } extends ... // 在对象里面, 算被抱着了

Utility Types 是 Partial, Required, 等这些东西

Mapped types 是 { [P in TKeys] : any }

object literals 是 { name: string }

2. Number Enums as flags

flags 这个概念 c# 也有 (点这里这里), 经常看到 enum 可以配合 | 来用, 比如 :

PropertyInfo[] attrs = obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); //获取attrs

简单理解就是把一个 enum 变成 类似 enum list

typescript 也允许我们做到这点. 点这里

首先定义 enum 的时候需要多写一些号码和符号进去进去 (这里用到的是二进制的移位方法, 我不太懂)

enum Abc {
A = 0,
B = 1 << 0,
C = 1 << 1,
D = 1 << 2,
E = 1 << 3
}

然后呢,就可以这样子去使用了.

let x: Abc = Abc.A | Abc.B;
if(x & Abc.B) {
console.log('has B');
}
const hasB = !!(x & Abc.B); // true
const hasC = !!(x & Abc.C); // false

书里有写它的原理,和如果添加移除,但我目前没有使用到,所以就不研究了.

2.1 扩展特定 enum 方法

通过 namespace

enum Abc {
A
}
namespace Abc {
export function print(): string {
return 'dada';
}
}
Abc.print()

3. 理解 target 和 lib 点这里

target es6 的话, lib 就会有 promise 这些东西.

有些时候我们想分开来管理.

target 指的是 output 出来的 js 等级

比如 es5, 那么它就不会有 Promise, Set, Map 之类的.

lib 是我们开发环境用的. 我们当然希望什么都有咯.

所以一个比较合理的做法就是,

target es5 出来的 js 是 es5

lib dom, es6, 开发的时候我们用的 es6 的 js

然后通过 Polyfill 来补上就好了.

4. declare overload method 点这里

没有 overload 的情况下可以这样 declare, 或者用 interface 也可以

type LongHand = {
(a: number): number;
};
type ShortHand = (a: number) => number;

overload 情况下只可以用第一种

type LongHandAllowsOverloadDeclarations = {
(a: number): number;
(a: string): string;
};

5. 兼容性和变体 点这里

兼容性是指一个类型是否可以当另一个类型来使用 (有时候过多的限制会让代码很难写,所以哪怕是强类型我们也经常会要强转之类的, 所以不可以档死了)

对象结构

type IsExtends<T, U> = T extends B ? true : false;
type A = { age: number };
type B = { age: number, name: string }; // 属性可以多, 不可以少
type result1 = IsExtends<B, A>; // true

函数参数

type Method = (age: number) => void;
type Method2 = () => void; // 参数可以少, 不可以多
type result2 = IsExtends<Method2, Method>; // true

上面都是比较简单的例子,只是数量上的问题

复杂的情况是参数类型,返回类型这些.

比如 2 个方法对比, 第 1 个参数类型是子类, 第 2 个是父类, 这个能兼容吗 ?

说到这里可能就需要引入变体的概念了

点这里

首先讲一下定义

A ≼ B 意味着 A 是 B 的子类型。

A → B 指的是以 A 为参数类型,以 B 为返回值类型的函数类型。

协变(Covariant):只在同一个方向;

逆变(Contravariant):只在相反的方向;

双向协变(Bivariant):包括同一个方向和不同方向 (通常这个是不安全的,但有时候没有办法就比如强转一样)

不变(Invariant):如果类型不完全相同,则它们是不兼容的。

来一个函数类型的例子, 2个函数是否可兼容依据参数类型和返回类型

灰狗 ≼ 狗 ≼ 动物

有一个方法是 狗 → 狗

那么怎样的方法是和它兼容的 ?

1. 灰狗 → 灰狗

2. 灰狗 → 动物

3. 动物 → 动物

4. 动物 → 灰狗 (正解)

参数类型默认情况下是双向的 (开启 strictFunctionTypes 之后就换成逆变),也就是说,只要是父类或者子类都 ok,返回类型是协变的,所以 a extends b 的话, a 的返回子类是 ok 的.

没开启 strictFunctionTypes 的时候

type methodParent = (p: Parent) => Parent;
type methodChild = (c: Child) => Child;
type result = IsExtends<methodChild, methodParent>; // true

开启之后就不行了, 改成父类就 ok

type methodParent = (p: Parent) => Parent;
type methodChild = (c: Parent) => Child;
type result = IsExtends<methodChild, methodParent>; // true

为什么参数是逆变的, 而返回值是协变的呢 ?

继承的概念就是我可以用 B 去替代 A. A 方法可以跑的地方,我全部换成 B 方法,它也要可以跑.

假设方法 A 的参数是狗 (要求抽象), 那么调用 A 方法的时候就有可能传入狗或者灰狗 (要求抽象, 但也可以传入具体).

如果 B 方法的参数是灰狗 (要求具体), 而我拿 B 替换了 A, 当调用的人传入狗的时候就不 ok 了 (因为 A 只要求抽象,所以调用的人可能传入抽象, 但是 B 内部却需要具体, 所以直接翻车).

所以参数是逆变的. (参数需要更抽象才行)

假设返回值 A 是狗 (给予具体), 那么获取返回值之后使用的就是具体属性.

如果返回值 B 是动物 (给予更抽象), 那么就翻车了咯

所以返回值是协变的 (返回值要更具体)

协变就是说要求 A 类的地方可以用 A 或 A 的子类来替换 (不可以用 A 的父类), 更具体

逆变就是要求 A 类的地方可以用 A 或 A 的父类来替换 (不可以用 A 的子类). 更抽象

双向就是上面 2 个都可以

不变就是 A 只能用 A 不可以是其它的

6. Conditional, Infer

refer : https://fettblog.eu/typescript-union-to-intersection/ (联合类型转交叉类型)

当 contional 遇到 union (Distributive Conditional Types)

如果是 naked 的话会被拆成多个来解析, not naked 的话就是把 T 传过去用而已

type Naked<T> = T extends any ? { name: T } : never;
type result = Naked<'a' | 'b'>; // { name: 'a' } | { name: 'b' } type NotNaked<T> = T[] extends any ? { name: T } : never;
type result2 = NotNaked<'a' | 'b'>; // { name: 'a' | 'b' }

Infer 有个特色就是如果 infer 是用在参数类型上, 由于是逆变 position, 最终出来的结果会变成交叉类型.

如果不是逆变的话,出来的结果会是联合类型

// 这是转为联合类型
type Foo<T> = T extends { a: infer U, b: infer U } ? U : never;
type T10 = Foo<{ a: string, b: string }>; // string
type T11 = Foo<{ a: string, b: number }>; // string | number
// 这是转为交叉类型
type Bar<T> = T extends { a: (x: infer U) => void, b: (x: infer U) => void } ? U : never;
type T20 = Bar<{ a: (x: string) => void, b: (x: string) => void }>; // string
type T21 = Bar<{ a: (x: string) => void, b: (x: number) => void }>; // string & number

这几招通常用在转换 union to array, union to intersection 等

Angular 学习笔记 (Typescript 高级篇)的更多相关文章

  1. Asp.net core Identity + identity server + angular 学习笔记 (第五篇)

    ABAC (Attribute Based Access Control) 基于属性得权限管理. 属性就是 key and value 表达力非常得强. 我们可以用 key = role value ...

  2. Asp.net core Identity + identity server + angular 学习笔记 (第四篇)

    来说说 RBAC (role based access control) 这是目前全世界最通用的权限管理机制, 当然使用率高并不是说它最好. 它也有很多局限的. 我们来讲讲最简单的 role base ...

  3. Asp.net core Identity + identity server + angular 学习笔记 (第三篇)

    register -> login 讲了 我们来讲讲 forgot password -> reset password  和 change password 吧 先来 forgot pa ...

  4. angular学习笔记(三十一)-$location(2)

    之前已经介绍了$location服务的基本用法:angular学习笔记(三十一)-$location(1). 这篇是上一篇的进阶,介绍$location的配置,兼容各版本浏览器,等. *注意,这里介绍 ...

  5. angular学习笔记(三十一)-$location(1)

    本篇介绍angular中的$location服务的基本用法,下一篇介绍它的复杂的用法. $location服务的主要作用是用于获取当前url以及改变当前的url,并且存入历史记录. 一. 获取url的 ...

  6. angular学习笔记(三十)-指令(10)-require和controller

    本篇介绍指令的最后两个属性,require和controller 当一个指令需要和父元素指令进行通信的时候,它们就会用到这两个属性,什么意思还是要看栗子: html: <outer‐direct ...

  7. angular学习笔记(三十)-指令(7)-compile和link(2)

    继续上一篇:angular学习笔记(三十)-指令(7)-compile和link(1) 上一篇讲了compile函数的基本概念,接下来详细讲解compile和link的执行顺序. 看一段三个指令嵌套的 ...

  8. angular学习笔记(三十)-指令(7)-compile和link(1)

    这篇主要讲解指令中的compile,以及它和link的微妙的关系. link函数在之前已经讲过了,而compile函数,它和link函数是不能共存的,如果定义了compile属性又定义link属性,那 ...

  9. angular学习笔记(三十)-指令(6)-transclude()方法(又称linker()方法)-模拟ng-repeat指令

    在angular学习笔记(三十)-指令(4)-transclude文章的末尾提到了,如果在指令中需要反复使用被嵌套的那一坨,需要使用transclude()方法. 在angular学习笔记(三十)-指 ...

  10. angular学习笔记(三十)-指令(5)-link

    这篇主要介绍angular指令中的link属性: link:function(scope,iEle,iAttrs,ctrl,linker){ .... } link属性值为一个函数,这个函数有五个参数 ...

随机推荐

  1. 【数据集】Maple-IDS——网络安全恶意流量检测数据集

    一.数据集介绍 Maple-IDS数据集是一个网络入侵检测评估数据集,旨在增强异常基础入侵检测系统(IDS)和入侵预防系统(IPS)的性能和可靠性.随着网络空间安全领域攻击的日益复杂化,拥有一个可靠和 ...

  2. 可视化—gojs 超多超实用经验分享(四)

    目录 41.监听连线拖拽结束后的事件 42.监听画布的修改事件 43.监听节点被 del 删除后回调事件(用于实现调用接口做一些真实的删除操作) 44.监听节点鼠标移入移出事件,hover 后显示特定 ...

  3. .NET Core 3.x 基于Autofac的AOP缓存

    一.依赖包 二.定义一个简单的缓存接口 /// <summary> /// 简单的缓存接口,只有查询和添加,以后会进行扩展 /// </summary> public inte ...

  4. 爆破字典:linux 敏感文件-01

    linux 中敏感文件 1.0 /apache/apache/conf/httpd.conf /apache/apache2/conf/httpd.conf /apache/php/php.ini / ...

  5. Jmeter函数助手24-longSum

    longSum函数可用于计算两个或多个长值的和.intSum函数参数值的范围在-2147483648到2147483647之间,而longSum函数的参数值范围比intSum的大. First lon ...

  6. 【Git】介绍与概述

    版本控制工具应该具备的功能? 协同修改 多人并行不悖的修改服务器端的同一个文件. 数据备份 不仅保存目录和文件的当前状态,还能够保存每一个提交过的历史状态. 版本管理 在保存每一个版本的文件信息的时候 ...

  7. 【SpringBoot】13 数据访问P1 整合Jdbc

    SpringBoot与数据访问概述: 对于数据访问层,无论是SQL还是NOSQL,Spring Boot默认采用整合Spring Data的方式进行统一处理, 添加大量自动配置,屏蔽了很多设置.引入各 ...

  8. 特斯拉在感知网络架构引入BEV三维空间转化层

    Learnging Where To Look End-to-End

  9. 【转载】 源码分析multiprocessing的Value Array共享内存原理

    原文地址: http://xiaorui.cc/archives/3290 ========================================================= 当第一次 ...

  10. 【转载】 解决VSCode运行或调试python文件无反应的问题

    ---------------- 版权声明:本文为CSDN博主「姜行者」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明.原文链接:https://blog.csdn. ...