6.TS类型保护和类型变换


TS 类型保护

这两个部分不那么重要,记点可能用的上的

类型保护就是通过关键字判断出分支中的类型

typeof

function double(input: string | number | boolean) {
  if (typeof input === "string") {
    return input + input;
  } else {
    if (typeof input === "number") {
      return input * 2;
    } else {
      return !input;
    }
  }
}

instanceof

class Animal {
  name!: string;
}
class Bird extends Animal {
  swing!: number;
}
function getName(animal: Animal) {
  if (animal instanceof Bird) {
    console.log(animal.swing);
  } else {
    console.log(animal.name);
  }
}

null 保护

开启了 strictNullChecks 选项,那么对于可能为 null 的变量不能调用它上面的方法和属性

function getFirstLetter(s: string | null) {
  //第一种方式是加上null判断
  if (s == null) {
    return "";
  }
  //第二种处理是增加一个或的处理
  s = s || "";
  return s.charAt(0);
}
//它并不能处理一些复杂的判断,需要加非空断言操作符
function getFirstLetter2(s: string | null) {
  function log() {
    console.log(s!.trim());
  }
  s = s || "";
  log();
  return s.charAt(0);
}

链判断运算符(?)

a?.b; //如果a是null/undefined,那么返回undefined,否则返回a.b的值.
a == null ? undefined : a.b;

可辨识的联合类型

在 interface 或 type 定义时 写好用于辨识的字段

interface WarningButton{
  class:'warning',
  text1:'修改'
}
interface DangerButton{
  class:'danger',
  text2:'删除'
}
type Button = WarningButton|DangerButton;
function getButton(button:Button){
 if(button.class=='warning'){
  console.log(button.text1);
 }
 if(button.class=='danger'){
  console.log(button.text2);
 }

in 判断type的属性

interface Bird { swing: number; }

interface Dog { leg: number; }

function getNumber(x: Bird | Dog) {
    if ("swing" in x) {
      return x.swing;
    }
    return x.leg;
}

is 自定义类判断

interface Bird {
  swing: number;
}

interface Dog {
  leg: number;
}

//没有相同字段可以定义一个类型保护函数
function isBird(x:Bird|Dog): x is Bird{
  return (<Bird>x).swing == 2;
  //return (x as Bird).swing == 2;
}

function getAnimal(x: Bird | Dog) {
  if (isBird(x)) {
    return x.swing;
  }
  return x.leg;
}

类型变换

类型推断

TS能根据赋值,推断 没用定义类型的变量的类型

let foo = 1; // foo 是 'number'
let bar = 'zhufeng'; // bar 是 'string'
foo = bar; // Error: 不能将 'string' 赋值给 `number`

const person = {
    name: 'zhufeng',
    age: 11
};
let name =person.name;
let age =person.age;
age = 'hello'; // Error:不能把 'string' 类型赋值给 'number' 类型

& 交叉类型

把多个类型拼成一个类型,具有所有类型的所需属性

interface Bird {
    name: string,
    fly(): void
}
interface Person {
    name: string,
    talk(): void
}
type BirdPerson = Bird & Person;
let p: BirdPerson = { name: 'zhufeng', fly() { }, talk() { } };
p.fly;
p.name
p.talk;

typeof 获取变量的类型,反射?

//先定义变量,再定义类型
let p1 = {
    name:'zhufeng',
    age:10,
    gender:'male'
}
type People = typeof p1;
function getName(p:People):string{
    return p.name;
}
getName(p1);

[]获取一个type内的子type

interface Person{
    name:string;
    age:number;
    job:{
        name:string
    };
    interests:{name:string,level:number}[]
}
let FrontEndJob:Person['job'] = {
    name:'前端工程师'
}
let interestLevel:Person['interests'][0]['level'] = 2;

keyof 创建联合类型

interface Person{
  name:string;
  age:number;
  gender:'male'|'female';
}
type PersonKey = keyof Person;
//type PersonKey = 'name'|'age'|'gender';

其他:模块

在默认情况下,当你开始在一个新的 TypeScript 文件中写下代码时,它处于全局命名空间中

这样的话,明明是不同的文件,却会产生命名冲突.

在工作中编码时却并没发现这种不同文件的同名冲突情况,

这是因为,

如果在你的 TypeScript 文件的 根级别位置含有 import 或者 export,

那么它会在这个文件中创建一个本地的作用域,称为 文件模块

AMD:不要使用它,它仅能在浏览器工作;

SystemJS:这是一个好的实验,已经被 ES 模块替代;

ES 模块:它并没有准备好。

TS系列完结


文章作者: 罗紫宇
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 罗紫宇 !
  目录