ts 是什么?
- Typescript 是JavaScript的超集,遵循ES5/ES6规范,扩展了Javascript语法;
- 越来越多的项目是基于TS,VSCode、Angular6、Vue3、React16;
- TS提供的类型系统可以帮助我们在写代码的时候提供更丰富的语法提示;
- 在创建前的编译阶段经过类型系统的检查,就可以避免很多线上的错误
ts安装和编译
npm install typescript -g
tsc hello.ts
tsc hello.ts hello1.ts hello2.ts
在开发的过程中,不同文件中出现同变量名是会出现冲突。可以在文件中添加
export {}
tsc --init // 生成配置文件tsconfig.json
tsc // 全局编译
tsc --watch // 文件改变自动编译
tsconfig.json
{
"compilerOptions": {
/* Basic Options */
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. 指定ECMAScript的目标版本*/
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. 指定模块代码的生成方式*/
// "lib": [], /* Specify library files to be included in the compilation. 指定编译的时候用来包含的编译文件*/
// "allowJs": true, /* Allow javascript files to be compiled. 允许编译JS文件*/
// "checkJs": true, /* Report errors in .js files. 在JS中包括错误*/
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. 指定JSX代码的生成方式 是保留还是react-native或者react*/
// "declaration": true, /* Generates corresponding '.d.ts' file.生成相应的类型声明文件 */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. 为每个类型声明文件生成相应的sourcemap*/
// "sourceMap": true, /* Generates corresponding '.map' file. 生成对应的map文件 */
// "outFile": "./", /* Concatenate and emit output to single file. 合并并且把编译后的内容输出 到一个文件里*/
// "outDir": "./", /* Redirect output structure to the directory.按原始结构输出到目标目录 */
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. 指定输入文件的根目录,用--outDir来控制输出的目录结构*/
// "composite": true, /* Enable project compilation 启用项目编译*/
// "removeComments": true, /* Do not emit comments to output. 移除注释*/
// "noEmit": true, /* Do not emit outputs. 不要输出*/
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. 当目标是ES5或ES3的时候提供对for-of、扩展运算符和解构赋值中对于迭代器的完整支持*/
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule').r把每一个文件转译成一个单独的模块 */
/* Strict Type-Checking Options */
//"strict": true, /* Enable all strict type-checking options. 启用完全的严格类型检查 */
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. 不能使用隐式的any类型*/
// "strictNullChecks": true, /* Enable strict null checks. 启用严格的NULL检查*/
// "strictFunctionTypes": true, /* Enable strict checking of function types. 启用严格的函数类型检查*/
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions.启用函数上严格的bind call 和apply方法 */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. 启用类上初始化属性检查*/
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type.在默认的any中调用 this表达式报错 */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. 在严格模式下解析并且向每个源文件中发射use strict*/
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. 有未使用到的本地变量时报错 */
// "noUnusedParameters": true, /* Report errors on unused parameters. 有未使用到的参数时报错*/
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. 当不是所有的代码路径都有返回值的时候报错*/
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. 在switch表达式中没有替代的case会报错 */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). 指定模块的解析策略 node classic*/
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. 在解析非绝对路径模块名的时候的基准路径*/
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. 一些路径的集合*/
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. 根目录的列表,在运行时用来合并内容*/
// "typeRoots": [], /* List of folders to include type definitions from. 用来包含类型声明的文件夹列表*/
// "types": [], /* Type declaration files to be included in compilation.在编译的时候被包含的类型声明 */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking.当没有默认导出的时候允许默认导入,这个在代码执行的时候没有作用,只是在类型检查的时候生效 */
//"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'.*/
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks.不要symlinks解析的真正路径 */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. 指定ts文件位置*/
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. 指定 map文件存放的位置 */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. 源文件和sourcemap 文件在同一文件中,而不是把map文件放在一个单独的文件里*/
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. 源文件和sourcemap 文件在同一文件中*/
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. 启动装饰器*/
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
}
}
ts数据类型
- 任意类型(any): 声明为 any 的变量可以赋予任意类型的值;
let b:any = 1;
- any就是可以赋值给任意类型
- 第三方库没有提供类型文件时可以使用any
- 类型转换遇到困难时
- 数据结构太复杂难以定义
- 数字类型(number)
let age:number = 18;
- 字符串类型(string)
let name: string = 'cc'
- 布尔类型(boolean)
let flag: boolean = true
- 数组类型(array)
// 在元素类型后面加上[]
let arr: number[] = [1, 2, 3]
// 使用数组泛型
let arr: Array = [1, 2, 3]
- 元组类型(tuple): 元组类型用来表示已知元素数量和类型的数组,各元素的类型不必相同,对应位置的类型需要相同。
let p: [string, age] = ['cc', 18]
元组 vs 数组
元组 | 数组 |
---|---|
每一项可以是不同的类型 | 每一项都是同一种类型 |
有预定义的长度 | 没有长度限制 |
用于表示一个固定的结构 | 用于表示一个列表 |
- 枚举类型(enum):枚举类型用于定义数值集合;默认情况下,从0开始为元素编号。也可手动修改指定成员的数值。
enum Color { Red, Green, Blue };
let c: Color = Color.Blue;
console.log(c); // 输出 2
- void:用于标识方法返回值的类型,表示该方法没有返回值
function hello(name: string):void {
console.log(`hello, ${name}`)
}
注:
- 当我们声明一个变量类型是 void 的时候,它的非严格模式(strictNullChecks:false)下仅可以被赋值为 null 和 undefined;
- 严格模式(strictNullChecks:true)下只能返回undefined
- null 和 undefined
- null 和 undefined 是其它类型的子类型,可以赋值给其它类型
- 严格模式(strictNullChecks:true)下不属于任何一个类型,只能赋值给自己这种类型或者any
// 非严格
let a: number;
a = null
a = undefined
// 严格
let b: number | undefined | null;
b = 1;
b = null;
b = undefined;
- never:never 是其它类型(包括 null 和 undefined)的子类型,代表从不会出现的值。
- 抛出异常的情况
- 无限循环的情况
never 和 void 的区别?
- void 可以被赋值为 null 和 undefined的类型。 never 则是一个不包含值的类型
- 拥有 void 返回值类型的函数能正常运行。拥有 never 返回值类型的函数无法正常返回,无法终止,或会抛出异常。
ts变量声明
- 联合类型(Union Types): 表示取值可以为多种类型中的一种。
注:在未赋值时联合类型上只能访问两个类型共有的属性和方法。
let ss: string | number;
// 在这里只能获取 string 和 number 类型的共有属性和方法
if (typeof ss === 'string') {
// 可以获取字符串的属性和方法
} else {
// 可以获取数值的属性和方法
}
- 类型断言(Type Assertion): 类型断言可以用来手动指定一个值的类型,即允许变量从一种类型更改为另一种类型。
程序员 强行告诉ts是一个什么类型。
// <类型>值
let str:string = '1'
let str1:number = str
console.log(str1)
// 值 as 类型
let ss: string | number;
let s = (ss as string).length;
let n = (ss as number).toFixed(2);
- 当 S 类型是 T 类型的子集,或者 T 类型是 S 类型的子集时,S 能被成功断言成 S。
- 当你在TypeScript里使用JSX时,只有 as 语法断言是被允许的。
- 类型推断:当类型没有给出时,ts 编译器利用类型推断来推断类型。
- 定义时未赋值就会被推断成any类型
- 定义时赋值就能利用类型推断出类型
let s; // 定义时未赋值,推断成any
s = 1;
s = '1';
let num = 1 // 定义赋值,类型推断为 number;
num = '1' // 再次赋值就会编译错误
- 字面量类型: 可以把字符串、数字、布尔值字面量组成一个联合类型
type cType = 1 | '1' | true
let c: cType = 1 // 变量c 为 1 '1' true 三者之一
- 交叉类型:将多个类型合并为一个类型。它包含了所有类型的特性。
interface Person {
id: string,
name: string
}
interface Master {
age: number
}
type Staff = Person & Master
const staff: Staff = {
id: '007',
name: 'cc',
age: 10
}
函数
- ts函数 vs js函数
TypeScript | JavaScript |
---|---|
含有类型 | 无类型 |
箭头函数 | 箭头函数(ES2015) |
函数类型 | 无函数类型 |
必填和可选参数 | 所有参数都是可选的 |
默认参数 | 默认参数 |
剩余参数 | 剩余参数 |
函数重载 | 无函数重载 |
- 函数的定义: 可以指定参数的类型和返回值的类型
function sayName(name: string): string {
return `hello, ${name}`
}
- 函数表达式
// 定义一个类型,用来约束函数表达式
type info = (name: string, age: number) => string;
let p: info = function(name: string, age: number): string {
return `hi, my name is ${name}, I'am ${age} years old`
}
p('cc', 19)
函数调用
实参的类型和个数必须和形参一一对应可选参数
可选参数必须是最后一个参数。
function buildName(firstName: string, lastName?: string) {
if (lastName) {
return firstName + lastName
}
return firstName
}
buildName('c')
buildName('c', 'pc')
- 默认参数
function person(name: string, age:number = 18): void {
console.log(age)
}
- 剩余参数
function sum(...numbers:number[]) {
return numbers.reduce((val,item)=>val+=item,0);
}
- 重载是方法名字相同,而参数数量或者类型不同,返回类型可以相同也可以不同。
// 为一个函数提供多个函数定义
function double(v: number): number; // 函数声明
function double(v: string): string; // 函数声明
function double(v: any): any { // 函数的实现,必须紧跟在函数声明后面
if (typeof v === 'number') return v * 2
if (typeof v === 'string') return v + v
}
类
- 定义类
- "strictPropertyInitialization": true // 启用类属性初始化的严格检查
- 属性初始化并赋值;greeting: string = 'cc';
- 添加constructor(greeting: string) { this.greeting = greeting }
- greeting!: string;
class Greeter {
greeting: string;
constructor(greeting: string) {
this.greeting = greeting
}
greet(): string {
return 'Hello, ' + this.greeting; // this 表示的是类的成员
}
}
let greeter = new Greeter('cc')
public
可以省略
class Greeter {
constructor(public greeting: string) {}
}
- readonly
-
readonly
修饰的变量只能在构造函数
中初始化 -
readonly
只是在编译阶段进行代码检查。而const
在运行时检查
class Person {
public readonly name: string;
constructor(name: string) {
this.name = name
}
}
let p = new Person('cc')
// p.name = 'yy'
- 修饰符
- puclic: 自己、子类、其他都可以访问
- protected: 自己和子类可以访问,其他不能访问
- private: 只能自己访问,子类和其他不能访问
class Father {
public readonly name: string = 'dad';
protected age: number = 10;
private money: number = 10000;
}
class Son extends Father {
getName(): void {
console.log(this.name)
}
getAge(): void {
console.log(this.age)
}
// getMoney(): void {
// console.log(this.money) // money 为私有属性
// }
}
- 类的继承
extends
- 一次只能继承一个类,不支持继承多个类,但 TypeScript 支持多重继承(A 继承 B,B 继承 C)
- 继承:子类继承父类,子类除了拥有父类的所有特性外,还有一些更具体的特性
- 多态:由继承而产生了相关的不同的类,对同一个方法可以有不同的行为
类的静态属性和静态方法
static
抽象类
abstract
- 抽象类是行为的抽象,一般来封装一些公共属性和方法
- 无法被实例化,只能被继承
- 抽象方法不能在抽象类中实现,只能在抽象类的具体子类中实现,而且
必须
实现
abstract class Person {
name!:string;
abstract say():void;
}
class Man extends Person {
say():void {
console.log('Nice!')
}
}
- 接口里的方法都是抽象的
- 实现接口
implements
- 一个类只能继承一个父类,但是可以实现多个接口
interface Runing {
run(): void;
}
interface Eating {
eat(): void;
}
class Man extends Person implements Runing, Eating {
say(): void {}
run(): void {}
eat(): void {}
}
- 重写
- 重写:子类重写继承自父类中的方法
- 重载:为同一个函数提供多个类型定义
接口
- 接口一方面可以在面向对象编程中表示为
行为的抽象
,另外可以用来描述对象的形状
- 接口就是把一些类中
共有的属性和方法
抽象出来,可以用来约束
实现此接口的类
- 定义接口
//接口可以用来描述`对象的形状`,少属性或者多属性都会报错
interface Speakable{
speak(): void;
name?: string; // ?表示可选属性
}
let speakman:Speakable = {
speak() {},//少属性会报错
name: 'cc',
// age: 1//多属性也会报错
}
- 任意属性
// 无法预先知道有哪些新的属性的时候,可以使用 `[propName:string]: any`,propName名字是任意的
interface Person {
readonly id: number;
name: string;
[propName: string]: any;
}
- 接口的继承
extends
- 函数类型接口:对方法传入的参数和返回值进行约束
interface computedAge {
(birth: number): number
}
let getAge: computedAge = function(birth: number): number {
return 2020 - birth
}
interface sumInterface {
(...args: number[]): number
}
let sum: sumInterface = (...args: number[]): number {
return args.reduce((a, b) => a + b, 0)
}
- 可索引接口:对数组或者对象进行约束
interface Interface1 {
[index: number]: string
}
interface Interface2 {
[index: string]: string
}
泛型
- 软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑
可重用性
。组件不仅能够支持当前
的数据类型,同时也能支持未来
的数据类型,这在创建大型系统时为你提供了十分灵活的功能。 - 泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性
- 设计泛型的关键目的是在成员之间提供有意义的约束,这些成员可以是:类的实例成员、类的方法、函数参数和函数返回值。
- 泛型类 用到了泛型的类
class CustomerGeneric {
zeroValue: T;
add: (x: T, y: T) => T;
}
- 泛型接口
interface Point {
a: A;
b: B;
}
function point (a: A, b: B): Point {
return { a, b }
}
point(1, 3)
- 泛型参数默认类型
interface A {
name: T;
}
let sa = { name: 'cc' }
let na = { name: 18 }
- 泛型的约束
interface LengthWise {
length: number
}
function logger(val: T) {
console.log(val.length) // 可以获取length属性
}
- 泛型工具类型
5.1 Partial:将某个类型里的属性全部变为可选项 ?
type Partial = {
[P in keyof T]?: T[P];
};
5.2 Required: 将传入的属性中的可选项变为必选项
type Required = { [P in keyof T]-?: T[P] };
5.3 Readonly:通过为传入的属性每一项都加上 readonly 修饰符来实现
type Readonly = { readonly [P in keyof T]: T[P] }
5.4 Pick: 能够帮助我们从传入的属性中摘取某一项返回
type Pick = { [P in K]: T[P] };
5.5 Exclude: 将某个类型中属于另一个的类型移除掉
type Exclude = T extends U ? never : T;
5.6 Record: 将 K 中所有的属性的值转化为 T 类型
type Record = {
[P in K]: T;
};
- 一些常见泛型变量代表的意思:
- T(Type):表示一个 TypeScript 类型
- K(Key):表示对象中的键类型
- V(Value):表示对象中的值类型
- E(Element):表示元素类型
类型变换
- 交叉类型: 把多个类型合并成一个大的总类型
interface Bird {
name: string
fly(): void
}
interface Person {
age: number;
talk(): void;
}
type BirdMan = Bird & Person
- typeof:获取一个变量的类型;
先拿到一个对象,然后通过对象获取,反推这个对象的类型
let p = { name: 'cc', age: 18 }
type Person = typeof p
let p1: Person = { name: 'yy', age: 17 }
- 索引访问操作符
interface Person {
location: {
city: string
}
}
let p: Person['location'] = { city: 'beijing' }
- keyof 操作符可以用来一个对象中的所有 key 值
interface Person {
name: string;
age: number;
}
type K1 = keyof Person; // "name" | "age"
type K2 = keyof Person[]; // "length" | "toString" | "pop" | "push" | "concat" | "join"
type K3 = keyof { [x: string]: Person }; // string | number
- 批量操作
interface Person {
name: string;
age: number
}
type PersonType = {
[key in keyof Person]?: Person[key] // 批量将参数变成可选参数
}