typeScritp的高级函数

2023-11-19

1.交叉类型

交叉类型是将多个类型合并为一个类型。 这让我们可以把现有的多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性。 例如, Person & Serializable & Loggable同时是 Person 和 Serializable 和 Loggable。 就是说这个类型的对象同时拥有了这三种类型的成员。
我们大多是在混入(mixins)或其它不适合典型面向对象模型的地方看到交叉类型的使用。 (在JavaScript里发生这种情况的场合很多!) 下面是如何创建混入的一个简单例子:

const mergeFunct = <T,U>(obj1:T,obj2:U):T&U =>{
    // let res = {} as T & U
    let res = <T&U>{}
    res = Object.assign(obj1,obj2)
    return res
}
mergeFunct({a:'a'},{b:'b'})

2.联合类型

联合类型与交叉类型很有关联,但是使用上却完全不同。 偶尔你会遇到这种情况,一个代码库希望传入 number或 string类型的参数。 例如下面的函数:

type1 | type2 | type3 |type4

const getLengthFun = (context:number | string):number=>{
    if(typeof context === 'string'){
        return context.length
    }else{
        return context.toString().length
    }
}

3.类型的保护

3.1 typeof 的类型保护
这些typeof类型保护只有两种形式能被识别: typeof v === "typename"和 typeof v !== “typename”, "typename"必须是 “number”, “string”, "boolean"或 “symbol”。 但是TypeScript并不会阻止你与其它字符串比较,语言不会把那些表达式识别为类型保护。

const ValueList = ['abc',123]
const getRandomValue = ()=>{
    const num = Math.random() * 10
    if(num > 5){
        return ValueList[0]
    }else{
        return ValueList[1]
    }
}



const item = getRandomValue()
function isString(type:number | string):type is string{  //类型保护基本上就是这样子的函数来约束输入的值
    return typeof type === 'string'
}

if(isString(item)){
    console.log(item.length)
}else{
    console.log(item.toFixed())
}

3.2 instanceof的类型保护

instanceof类型保护是通过构造函数来细化类型的一种方式。 比如

	class CressByClass1{
    age = 213
}

class CressByClass2{
    name = 'asd'
}

function getRandom(){
    return Math.random() * 10 < 5 ? new CressByClass1() : new CressByClass2()
}

const item1 = getRandom()

if(item1 instanceof CressByClass1){
    console.log(item1.age)
}else{
    console.log(item1.name)
}

4.null / undefined

TypeScript具有两种特殊的类型, null和 undefined,它们分别具有值null和undefined.
默认情况下,类型检查器认为 null与 undefined可以赋值给任何类型。 null与 undefined是所有其它类型的一个有效值。 这也意味着,你阻止不了将它们赋值给其它类型,就算是你想要阻止这种情况也不行。

let s = "foo";
s = null; // 错误, 'null'不能赋值给'string'
let sn: string | null = "bar";
sn = null; // 可以

sn = undefined; // error, 'undefined'不能赋值给'string | null'

注意,按照JavaScript的语义,TypeScript会把 null和 undefined区别对待。 string | null, string | undefined和 string | undefined | null是不同的类型。

5.类型断言

	function getLengthStr(num:number | null):string{
    function gerRes(prefix:string){
        return prefix + num!.toFixed().toString()
    }

    num = num || 0.1

    return gerRes('lison-')
}

console.log(getLengthStr(9.39999))

6.类型别名

类型别名会给一个类型起个新名字。 类型别名有时和接口很像,但是可以作用于原始值,联合类型,元组以及其它任何你需要手写的类型。

type TypeString = string;
let str2 : TypeString

type PositionType<T> = {x:T,y:T}

const position1:PositionType<number> = {
    x : 1,
    y : -1
}

const position2:PositionType<string> = {
    x:'x',
    y:'y'
}

type Childs<T> = {
    current:T,
    child?:Childs<T>
}

使用接口也可以达到类型别名的作用

               使用接口也可以起到类型别名的作用
interface Alias {
    num:number
}

interface Interface{
    num:number
}

let _alia:Alias = {
    num:1
}

let inter:Interface = {
    num:2
}

_alia = inter


7.自变量类型

字面量类型允许你指定字符串必须的固定值。 在实际应用中,字符串字面量类型可以与联合类型,类型保护和类型别名很好的配合。 通过结合使用这些特性,你可以实现类似枚举类型的字符串。

type Name = 'Lison'
const name3:Name = 'Lison'

type Direction = 'north' | 'east' | 'south' | 'west'

function getDirectionFirstLetter(direction:Direction){
    return direction.substr(0,1)
}
console.log(getDirectionFirstLetter('east'))


type Age = 18;
interface InfoInterface {
    name:string;
    age:Age
}

const info:InfoInterface = {
    name:'aa',
    age:18
}

8.可辨识联合

你可以合并单例类型,联合类型,类型保护和类型别名来创建一个叫做 可辨识联合的高级模式,它也称做 标签联合或 代数数据类型。 可辨识联合在函数式编程很有用处。 一些语言会自动地为你辨识联合;而TypeScript则基于已有的JavaScript模式。 它具有3个要素:

  1. 具有普通的单例类型属性— 可辨识的特征。
  2. 一个类型别名包含了那些类型的联合— 联合。
  3. 此属性上的类型保护。
interface Square {
    kind:'square',
    size:number
}

interface Rectangle {
    kind:'rectangle',
    width:number,
    height:number
}

interface Circle {
    kind:'circle',
    radius:number
}

type Shape = Square | Rectangle | Circle

function asserNever(value:never):never {
    throw new Error('Unexpected onject' + value)
}

function getArea(s:Shape):number{
    switch(s.kind){
        case 'square':
            return s.size * s.size;
            break
        case 'rectangle':
            return s.height * s.width
            break
        case 'circle':
            return Math.PI * s.radius ** 2
            break;
        default: 
            return asserNever(s)
    }
}

9.this 类型

this类型表示的是某个包含类或接口的 子类型。 这被称做 F-bounded多态性。 它能很容易的表现连贯接口间的继承。

return this 之后就可以直接链式编程
class Counter {
    constructor(public count:number = 0){}
    
    add(value:number){
        this.count += value
        return this
    }

    subtract(value:number){
        this.count -= value
        return this
    }
}

const counter = new Counter(10)

console.log(counter.add(90).subtract(77))

class PowCounter extends Counter {
    constructor(public count:number = 0){
        super(count)
    }

    pow(value:number){
        this.count = this.count ** value
        return this
    }
}

const powcount = new PowCounter(2)

console.log(powcount.pow(3).add(1).subtract(7))

10.索引类型 keyof

使用索引类型,编译器就能够检查使用了动态属性名的代码。 例如,一个常见的JavaScript模式是从对象中选取属性的子集。

function pluck(o, names) {
    return names.map(n => o[n]);
}

下面是如何在TypeScript里使用此函数,通过 索引类型查询和 索引访问操作符:

function pluck<T, K extends keyof T>(o: T, names: K[]): T[K][] {
  return names.map(n => o[n]);
}

interface Person {
    name: string;
    age: number;
}
let person: Person = {
    name: 'Jarid',
    age: 35
};
let strings: string[] = pluck(person, ['name']); // ok, string[]

编译器会检查 name是否真的是 Person的一个属性。 本例还引入了几个新的类型操作符。 首先是 keyof T, 索引类型查询操作符。 对于任何类型 T, keyof T的结果为 T上已知的公共属性名的联合。 例如:

let personProps: keyof Person; // 'name' | 'age'

keyof Person是完全可以与 ‘name’ | 'age’互相替换的。 不同的是如果你添加了其它的属性到 Person,例如 address: string,那么 keyof Person会自动变为 ‘name’ | ‘age’ | ‘address’。 你可以在像 pluck函数这类上下文里使用 keyof,因为在使用之前你并不清楚可能出现的属性名。 但编译器会检查你是否传入了正确的属性名给 pluck:

pluck(person, ['age', 'unknown']); // error, 'unknown' is not in 'name' | 'age'

第二个操作符是 T[K], 索引访问操作符。 在这里,类型语法反映了表达式语法。 这意味着 person[‘name’]具有类型 Person[‘name’] — 在我们的例子里则为 string类型。 然而,就像索引类型查询一样,你可以在普通的上下文里使用 T[K],这正是它的强大所在。 你只要确保类型变量 K extends keyof T就可以了。 例如下面 getProperty函数的例子:

function getProperty<T, K extends keyof T>(o: T, name: K): T[K] {
    return o[name]; // o[name] is of type T[K]
}

getProperty里的 o: T和 name: K,意味着 o[name]: T[K]。 当你返回 T[K]的结果,编译器会实例化键的真实类型,因此 getProperty的返回值类型会随着你需要的属性改变。

let name: string = getProperty(person, 'name');
let age: number = getProperty(person, 'age');
let unknown = getProperty(person, 'unknown'); // error, 'unknown' is not in 'name' | 'age'

索引类型和字符串索引签名

keyof和 T[K]与字符串索引签名进行交互。 如果你有一个带有字符串索引签名的类型,那么 keyof T会是 string。 并且 T[string]为索引签名的类型:

interface Map<T> {
    [key: string]: T;
}
let keys: keyof Map<number>; // string
let value: Map<number>['foo']; // number

11.Readonly Partial Pick Record

Readonly 设置里面的全部为只读 – 系统自带的可以直接使用

interface Info1 {
    age:number,
    name:string,
    sex:string
}

type ReadyonlyType<T> = {
    readonly [P in keyof T] : T[P]   //这里面的 [P in keyof T] 相当于js 里面的数组的 for 循环 P 就相当于里卖的item.
}

type ReadonlyInfo1 = Readonly<Info1>

let info1:ReadonlyInfo1 = {
    age:19,
    name:'lison',
    sex:'man'
}

Partial 设置全部为可选 – 系统自带的可以直接使用

interface Info1 {
    age:number,
    name:string,
    sex:string
}

type PartialType<T> = {
    Partial  [P in keyof T] : T[P]  
}

type PartialInfo1 = Partial<Info1>

let info1:PartialInfo1 = {
    age:19,
    name:'lison',
    sex:'man'
}

Pick 是取部分值

type Pick<T,K extends keyof T> = {
    [P in K] : T[P]
}

interface Info {
    name:string,
    age:number,
    address:string
}

let info2:Info = {
    name:'xiao ming',
    age:19,
    address:'cahng sha'
}

function pick<T , K extends keyof T>(obj:T , keys:K[]):Pick<T , K>{ //Pick 是取部分
    const res:any = {};
    keys.map(item=>res[item] = obj[item])
    return res
}


const addname = pick(info2,['name','address'])

console.log(addname)

Record 这个就是将传入的属性转换为其他值得一种方法

function mapObject<K extends string | number,T ,U>(obj:Record<K,T>,f:(x:T)=>U):Record<K,U>{
    const res:any = {};
    for(const key in obj){
        res[key] = obj[key]
    }
    return res
}

const names = { 0:'hello',1:'world',2:'bye' }
const lengths = mapObject(names,s=>s.length)
console.log(lengths)

12.映射

一个常见的任务是将一个已知的类型每个属性都变为可选的:

interface PersonPartial {
    name?: string;
    age?: number;
}

或者我们想要一个只读版本:

interface PersonReadonly {
    readonly name: string;
    readonly age: number;
}

这在JavaScript里经常出现,TypeScript提供了从旧类型中创建新类型的一种方式 — 映射类型。 在映射类型里,新类型以相同的形式去转换旧类型里每个属性。 例如,你可以令每个属性成为 readonly类型或可选的。 下面是一些例子:

type Readonly<T> = {
    readonly [P in keyof T]: T[P];
}
type Partial<T> = {
    [P in keyof T]?: T[P];
}

像下面这样使用:

type PersonPartial = Partial<Person>;
type ReadonlyPerson = Readonly<Person>;

下面来看看最简单的映射类型和它的组成部分:

type Keys = 'option1' | 'option2';
type Flags = { [K in Keys]: boolean };

它的语法与索引签名的语法类型,内部使用了 for … in。 具有三个部分:

类型变量 K,它会依次绑定到每个属性。
1.字符串字面量联合的 Keys,它包含了要迭代的属性名的集合。
2.属性的结果类型。
3.在个简单的例子里, Keys是硬编码的的属性名列表并且属性类型永远是 boolean,因此这个映射类型等同于:

type Flags = {
    option1: boolean;
    option2: boolean;
}

在真正的应用里,可能不同于上面的 Readonly或 Partial。 它们会基于一些已存在的类型,且按照一定的方式转换字段。 这就是 keyof和索引访问类型要做的事情:

type NullablePerson = { [P in keyof Person]: Person[P] | null }
type PartialPerson = { [P in keyof Person]?: Person[P] }

在这些例子里,属性列表是 keyof T且结果类型是 T[P]的变体。 这是使用通用映射类型的一个好模版。 因为这类转换是 同态的,映射只作用于 T的属性而没有其它的。 编译器知道在添加任何新属性之前可以拷贝所有存在的属性修饰符。 例如,假设 Person.name是只读的,那么 Partial.name也将是只读的且为可选的。

13.由映射类型进行推断

type Proxy<T> = {
    get():T;
    set(value:T):void;
}
type Proxify<T> = {
  [P in keyof T]:Proxy<T[P]>
}
function proxify<T>(obj:T):Proxify<T>{
  const result = {} as Proxify<T>
  for (const key in obj){
    result[key] = {
      get:() => obj[key],
      set:(value) => obj[key] = value
    }
  }
  return result
}


let props = {
  name:'lison',
  age:20,
}

let porxyProps = proxify(props)

// porxyProps.name.set('wang')
// console.log(porxyProps.name.get())
function unproxify<T>(t:Proxify<T>):T{
  const result = {} as T
  for(const key in t){
    result[key] = t[key].get()
  }
  return result
}

console.log(unproxify(porxyProps))

元组的映射

type MapToPromise<T> = {
  [P in keyof T] : Promise<T[P]>
}
type Tuple = [number,string,boolean]

type promiseTuple = MapToPromise<Tuple>
let tuple1:promiseTuple = [
  new Promise((resolve,reject) => resolve(1)),
  new Promise((resolve,reject) => resolve('aa')),
  new Promise((resolve,reject) => resolve(false))
]

14.unknown

14.1 unknown 是任何类型都可以赋值给他

let value1:unknown;
value1 = 1
value1 = 'as'

14.2 如果没有类型断言和基于控制细化时,unknown 是不可以赋值给任何类型的

let value2:unknown;
let value3:string = value2
value2 = value1 //对象的类型为 "unknown"

14.3 如果没有类型断言和基于控制流细化时,unknown 是不能在它上面进行任何的操作

let value4 : unknown
value4 += 5;  //对象的类型为 "unknown"

14.4 unknown 与任何类型组成的交叉类型都会等于其他类型。

type type1 = string & unknown
type type2 = number & unknown
type type3 = unknown & unknown
type type4 = string & string[]

14.5 unknown 与任何类型组成联合类型都会等于 unknown

type type5 = unknown | string 
type type6 = unknown | number 
type type7 = unknown | any

14.6 nerve 是 unknown的子类型

type type8 = never extends unknown ? true : false

14.7 kerof unknown 等于nerve

 type type9 = keyof unknown

14.8 自能对unknown 进行等于和不等于操作,其他的操作是不可以的

value1 === value2
value1 !== value2

14.9 unknown类型的值是不能访问他的属性,作为函数调用和作为实列来声明

let value5:unknown
value5.age
value5()
new value5()

14.10 如果使用映射来遍历unknown ,是不会返回任何的值

type Types1<T> = {
  [P in keyof T]:number
}

type type10 = Types1<number>
type type11 = Types1<unknown>

15.条件类型

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

typeScritp的高级函数 的相关文章

随机推荐

  • 关于gitee的用法

    一 安装git 安装git git version 查看版本 创建仓库 git 全局配置 git config global user name huangkaihk git config global user email 邮箱 git
  • 2.6.1 ADSL技术

    ADSL技术 即 非对称数字用户线技术 利用 数字技术 对 现有的 模拟电话用户线 进行改造 使其能够承载宽带数字业务 标准模拟电话信号的 频带 被限制在 300 3400 Hz 的范围内 无法承载宽带数字业务 但 用户线本身 可通过的 信
  • 超详细!4小时开发一个SpringBoot+vue前后端分离博客项目!!

    小Hub领读 前后端分离的博客项目终于出来啦 真是花了好多心思录制咧 文末直接进入B站看视频哈 这次你找不到不关注我B站的理由了吧 作者 吕一明 项目代码 https github com MarkerHub vueblog 项目视频 ht
  • Unity卡死情况

    今天遇到了Unity点击播放后卡死 用任务管理器强行关闭后重开 打不开项目的情况 解决方案 检查USB接口设备 有些设备可能会影响Unity工程启动 比如VR头盔
  • 使用java代码给Excel加水印,代码全,进阶版

    以下代码 亲测可以跑通 1 上一篇博客用了Apache POI库3 8的版本的形式对Excel加了水印 但是最近主线版本用了4 1 2的形式 由于为了保持版本的兼容性 下面有开发了Apache POI的4 1 2的版本号的方案 pom文件为
  • 使用selenium IDE开始简易自动化测试

    使用selenium IDE开始简易自动化测试 火狐浏览器有个很好用的selenium插件 可以自动录制页面动作 selenium IDE 下载地址 下载安装好 笔者下载的2 9 0 我们以在百度搜索selenium为例 首先启动IDE 点
  • 链式二叉树的基本操作(C语言实现)

    目录 一 链式二叉树的创建 1 1 定义节点结构 1 2 节点的创建 1 3 节点的链接 二 树的深度遍历 1 前序 中序 后序遍历 1 2 三种方式的遍历顺序图 2 代码实现 3 遍历检测 三 树的层序遍历 3 1 层序遍历 3 2 完全
  • Loadrunner录制登录,验证是否登录成功的几种方法

    1 利用web reg find 优先使用 2 利用web image check 其次 3 利用web get int property函数 4 利用提交的status状态 5 利用对数据的操作查看是否登录 1 利用添加检查点web re
  • 拼多多招收java开发的三轮面试题,你能撑到第几轮?

    我相信 面试一直是大家关注的问题 包括最近有很多刚毕业或者刚实习的小伙伴跟我讲投了很多简历出去 但却都像泥牛入海一样了无音讯了 确实出于程序员的直觉 今年着实是要比往年要更冷一些 对于面试来说 我相信大家都听过一个说法就是 金九银十 但是现
  • c++/cuda并行累计求和

    文章目录 代码 CMakeLists txt 结果 代码 include
  • 设计模式-建造者模式

    文章目录 建造者模式 创建复杂对象的优雅方式 什么是建造者模式 建造者模式的使用场景 优缺点 示例 使用建造者模式创建电脑对象 建造者模式 创建复杂对象的优雅方式 在软件开发中 有时候我们需要创建具有复杂结构和多个组件的对象 直接在客户端代
  • 【Pytorch异常笔记】Error #15: Initializing libiomp5md.dll, but found libiomp5md.dll already initialized.

    文章目录 异常描述 解决方法 开发环境 异常描述 OMP Error 15 Initializing libiomp5md dll but found libiomp5md dll already initialized OMP Hint
  • git 和远程服务器关联,Git远程服务器连接被拒绝

    我对这个错误感到疯狂 2天后我没有发现我的系统出了什么问题 我相信修复它非常容易 Git远程服务器连接被拒绝 当我尝试使用Git功能我得到的消息 连接到我的git服务器 无法打开连接 主机不存在 致命的 无法从远程存储库中读取 请确保您拥有
  • Android JNI1--C语言基础

    1 include 相当于java的导包操作 例如 include
  • vue中computed的属性对data中的属性赋值为undefined的原因

    场景 我在computed中return了一个值 然后在data中直接将它复制给另一个属性 结果data中的属性值为undefined 代码示例 timer为undefined 原因 在这里很容易想到是执行顺序的问题 computed中的属
  • sql server 中的日期计算,如当天周的第一天,当前月的第一天

    根据给定的日期 计算该日期在本月所在周数 每周的第一天为周日 但是在月末需要与下个月进行衔接 如 图2012年2月份 3月份的1 2 3号为2月份的第4周 而2月份的1 2 3 4为1月份的最后一周 第五周 declare datetime
  • linux线程间通讯----管道、信号

    进程间通讯机制 unix继承 管道 信号 system V IPC对象 共享内存 消息队列 信号灯集 1 管道 管道分为无名管道和有名管道 区别在于创建的管道是否在文件系统中不可见 无名不可见 有名可见 1 无名管道 特点 1 在创建之后再
  • 系统调用详解

    1 系统调用 1 系统调用就是为了让应用程序可以访问系统资源 每个操作系统都会提供一套接口供应用程序使用 这些接口通常通过中断来实现 例如在windows中是0x2E号中断作为系统调用入口 linux使用0x80号中断作为系统的调用的入口
  • IC数字后端

    在 innovus 里面 有时候我们需要控制 tie cell 的 fanout 和 net length 来避免 tie cell 可能出现 max transition 或者 max fanout 的违例 一般来说 只要 fanout
  • typeScritp的高级函数

    1 交叉类型 交叉类型是将多个类型合并为一个类型 这让我们可以把现有的多种类型叠加到一起成为一种类型 它包含了所需的所有类型的特性 例如 Person Serializable Loggable同时是 Person 和 Serializab