Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typescript #59

Open
wuyanqian0503 opened this issue Jun 30, 2021 · 15 comments
Open

Typescript #59

wuyanqian0503 opened this issue Jun 30, 2021 · 15 comments

Comments

@wuyanqian0503
Copy link
Owner

TS是什么

JS的超集,向JS这个语言添加了可选的静态类型和基于类的面向对象编程。
并且它提供了最新和不断发展的JS新特性。

TS和JS的区别

  • JS是一种语言,TS是JS的超集,在JS的基础上扩展了很多新特性,最终也会编译成JS
  • TS可以在编译过程中检查代码错误,作为一种解释型语言,一边编译一边执行,只能在运行时发现错误
  • TS是强类型的,支持静态和动态类型,JS时若类型的,没有静态类型。
  • TS支持接口、模块、泛型、命名空间等
@wuyanqian0503
Copy link
Owner Author

安装与使用

1、使用npm进行安装

npm install -g typescript

2、验证Typescript安装版本

typescript 的命令为 tsc

tsc -v
Version 4.0.2

3、编译ts文件

tsc helloworld.ts

你也可以使用webpack的ts-loader帮助你在构建项目时进行编译。

@wuyanqian0503
Copy link
Owner Author

TS 中的基础类型

  • Boolean
  • Number
  • String
  • Symbol
  • Array
  • Enum:枚举,包含数字枚举,字符串枚举、常量枚举、异构枚举
  • Unknown:所有类型的值都可以赋值给unknown,但是unknown 类型只能被赋值给 any 类型和 unknown 类型本身
  • Tuple:元祖
  • Null
  • Undefined
  • object, Object 和 {} 类型
  • Any:全局超集类型,任何类型都可以被归为any
  • Void:没有任何类型,当函数没有返回值时可以被指定为void
  • Never:永远不存在值的类型

Never 类型

never 类型表示的是那些永不存在的值的类型。 例如,never 类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型。

// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
  throw new Error(message);
}

function infiniteLoop(): never {
  while (true) {}
}

在 TypeScript 中,可以利用 never 类型的特性来实现全面性检查,具体示例如下:

type Foo = string | number;

function controlFlowAnalysisWithNever(foo: Foo) {
  if (typeof foo === "string") {
    // 这里 foo 被收窄为 string 类型
  } else if (typeof foo === "number") {
    // 这里 foo 被收窄为 number 类型
  } else {
    // foo 在这里是 never
    const check: never = foo;
  }
}

注意在 else 分支里面,我们把收窄为 never 的 foo 赋值给一个显示声明的 never 变量。如果一切逻辑正确,那么这里应该能够编译通过。但是假如后来有一天你的同事修改了 Foo 的类型:
type Foo = string | number | boolean;

然而他忘记同时修改 controlFlowAnalysisWithNever 方法中的控制流程,这时候 else 分支的 foo 类型会被收窄为 boolean 类型,导致无法赋值给 never 类型,这时就会产生一个编译错误。通过这个方式,我们可以确保
controlFlowAnalysisWithNever 方法总是穷尽了 Foo 的所有可能类型。 通过这个示例,我们可以得出一个结论:使用 never 避免出现新增了联合类型没有对应的实现,目的就是写出类型绝对安全的代码。

@wuyanqian0503
Copy link
Owner Author

wuyanqian0503 commented Jun 30, 2021

TS 断言

类型断言

1、使用尖括号语法

let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;

注意:
在 TS 可以使用尖括号来表示类型断言,但是在结合 JSX 的语法时将带来解析上的困难。因此,TS 在 .tsx 文件里禁用了使用尖括号的类型断言。

而 as 操作符在 .ts 文件和 .tsx 文件里都可用。

2、或者as:

let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;

非空断言

使用感叹号!

x! 将从 x 值域中排除 null 和 undefined

可以对变量或者函数使用

  const ignoreUndefinedAndNull: string = maybeString!; // Ok
  const num2 = numGenerator!(); //OK

确定赋值断言

同样使用感叹号!

告诉编译器该变量会被明确赋值

// 直接在变量声明时断言
let x!: number;
initialize();
console.log(2 * x); // Ok

function initialize() {
  x = 10;
}

@wuyanqian0503
Copy link
Owner Author

类型守卫

类型保护是可执行运行时检查的一种表达式,用于确保该类型在一定的范围内。 换句话说,类型保护可以保证一个字符串是一个字符串,尽管它的值也可以是一个数值。类型保护与特性检测并不是完全不同,其主要思想是尝试检测属性、方法或原型,以确定如何处理值。目前主要有四种的方式来实现类型保护:

1、in
2、typeof
3、instanceOf
4、自定义类型保护如isNumber

@wuyanqian0503
Copy link
Owner Author

wuyanqian0503 commented Jun 30, 2021

联合类型和类型别名

联合类型

通常和undefined一起使用


function test(name: string | undefined) {
    // ...
}

可辨识联合

组成联合类型的各个类型存在公共属性

类型别名

type xxx = string | string[]

交叉类型

通过&运算符将多种类型叠加,它包含了所有类型的特性:

type PartialPointX = { x: number; };
type Point = PartialPointX & { y: number; };

let point: Point = {
  x: 1,
  y: 1
}

@wuyanqian0503
Copy link
Owner Author

wuyanqian0503 commented Jul 1, 2021

访问控制修饰符

有 public、private、protected

  • public:公共方法,任何地方都可以使用,默认情况下都是public的
  • private:私有方法,只能在定义的类中访问
  • protected:和private类似,但是区别是可以在子类中使用。

@wuyanqian0503
Copy link
Owner Author

重写(override) vs 重载(overload)

重写是指子类重写“继承”自父类中的方法 。虽然 TS 和JAVA 相似,但是 TS 中的继承本质上还是 JS 的“继承”机制—原型链机制
重载是指为同一个函数提供多个类型定义

@wuyanqian0503
Copy link
Owner Author

泛型

泛型就是我们在定义哈书、接口或者类的时候,先不指定类型,而是等到使用的时候再告知类型的一种特性:

// 定义函数时使用了类型变量T
function identity<T>(arg: T): T {
    return arg;
}

// 在使用函数时指定函数的入参类型 T 为 string类型
let output = identity<string>("myString");

把 T 称为类型变量,你也可以对同一个函数或者类设置多个类型变量,通过尖括号包裹,并且用逗号隔开:

function identity<T, S>(value1: T, value2: S): Array< T | S > {
    return [value1, value2];
}

@wuyanqian0503
Copy link
Owner Author

类型谓词

使用 is 关键词来指定函数参数的类型: parameterName is type

用于当函数入参的类型为联合类型时,通过类型谓词来指定类型进行自定义类型保护的作用

@wuyanqian0503
Copy link
Owner Author

?., !, ??

?. :可选链式运算符,先判断左侧表达式是否有值,如果有值,再访问右侧的属性,如果没有值则返回undefined,防止运行时报错,或者需要编写一长串的非空判断
!:非空断言运算符,告诉编译器左侧的表达式一定有值
??:空值合并运算符,当左侧表达式为null或undefined时会返回右侧表达式的值,和以前常用的 逻辑或运算符 || 的区别在于,排除了值为 0 或 “” 时被判定为假值的情况。

@wuyanqian0503
Copy link
Owner Author

模块

从ECMAScript 2015(ES6)开始,JavaScript引入了模块的概念。TypeScript也沿用这个概念。

模块拥有自己的作用域;这意味着定义在一个模块里的变量,函数,类等等在模块外部是不可见的,除非你明确地使用export形式之一导出它们。 相反,如果想使用其它模块导出的变量,函数,类,接口等的时候,你必须要导入它们,可以使用 import形式之一。

模块是自声明的;两个模块之间的关系是通过在文件级别上使用imports和exports建立的。

模块使用模块加载器去导入其它的模块。 在运行时,模块加载器的作用是在执行此模块代码前去查找并执行这个模块的所有依赖。 大家最熟知的JavaScript模块加载器是服务于Node.js的 CommonJS和服务于Web应用的Require.js。

TypeScript与ECMAScript 2015一样,任何包含顶级import或者export的文件都被当成一个模块。相反地,如果一个文件不带有顶级的import或者export声明,那么它的内容被视为全局可见的(因此对模块也是可见的)。

@wuyanqian0503
Copy link
Owner Author

wuyanqian0503 commented Jul 1, 2021

命名空间

命名空间是为了提供逻辑分组和避免命名冲突。

可以在命名空间中声明接口、类、变量、函数等,通过export来将他们导出。
你也可以将同一个命名空间分离到不同文件中分别编写。虽然是不同的文件,但他们还是同一个命名空间,通过三斜线指令来声明文件间的依赖,告诉编译器在编译过程中需要额外引入的文件

/// <reference path="Validation.ts" />

注意事项:

  • 当你使用模块时,在外部调用看来模块本身就已经是一个独立的分组,所以可以不必再通过命名空间再次添加层级。
  • 并且,模块本身就可以通过import这种方式来声明依赖,所以不要在模块中使用reference

@wuyanqian0503
Copy link
Owner Author

type 与 interface 的区别

两者在大多数情况下可以互相替代,并且可以互相扩展,但是也是存在一些细微区别:

1、type 可以使用计算属性,interface 不能
2、type 不支持同名合并,interface 支持

@wuyanqian0503
Copy link
Owner Author

wuyanqian0503 commented Jul 1, 2021

class和interface的区别

  • interface: TypeScript 中的接口是一个非常灵活的概念,除了可用于对类的一部分行为进行抽象以外,也常用于对**「对象的形状(Shape)」进行描述。通常我们通过接口约束**了传入变量的内容,当不遵守这个约定时,typescript就会抛出一个错误。

  • class:TypeScript 除了实现了所有 ES6 中的类的功能以外,还添加了一些新的用法。Typescript在创建类的同时也会创建一个同名的 interface,这个interface中包含了类的方法和属性,所以class作为类的同时也可以被作为interface来使用

@wuyanqian0503
Copy link
Owner Author

常用的Utility Types

Partial

构造一个类型,其所有属性的类型都设置为可选。此实用程序将返回表示给定类型的所有子集的类型。例如:


interface A {
  name:string;
  id:string
}

let a: Partial<A> = {
  name:'tangjie'
}
console.log(a)

Pick<Type, Keys>

通过从Type中选择属性键集(字符串、文字或字符串文本的联合)来构造类型。

interface A {
  id: string;
  name: string;
  age: number;
}
type B = Pick<A, "name" | "age">;

const xiaoming: B = {
  name: "xiaoming",
  age: 26,
};

Omit<Type, Keys>

通过从原类型中排除掉一些属性,来构造一个类型


interface A {
  id: string;
  name: string;
  age: number;
}

const a:Omit<A,'id'> = {
	name:'tangjie',
	age:18,
	// id:1 如果加了这个属性就报错
}

Parameters

从函数的参数中使用的类型构造元组类型。


declare function f1(arg: { a: number; b: string }): void;
type A = Parameters<() => string>;// 相当于A = []    
type B = Parameters<(s: string) => void>;// 相当于 B = [s: string]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant