TypeScript 学习笔记
TypeScript 的类型校验是给程序员看的,在编译后不会存在TS代码。
类型注解
function fn(person: string):void{ // 参数类型是字符串,没有返回值
///...
}
fn('str') // 如传递参数非字符串,vscode编辑器中或在编译时将给出错误提示
const test:number = 1
有哪些基础类型注解?
// 基础类型
:string
:number
:boolean
:null // 只能是null值
:undefined // 只能是undefined值
:symbol
// 引用类型
:object // 不常用,多使用接口来给对象进行类型注解
// 其他
:any // 任意类型
:void // 空,用于函数的无返回值的注解
:never // 用于标注函数代码永远执行不完(如抛出错误的函数,死循环函数)
什么是类型注解和类型推断、类型断言?
类型注解 是显式的标注类型
类型推断 是编辑器根据值来自动推断出类型 (编辑器中鼠标移到变量会显示类型的提示)。
类型断言 是告诉编译器,“相信我,它就是这个类型”。
// 类型注解就是显式的写出类型
const myNumber: number = 123
// 类型推断是根据值来推断类型 (鼠标移到变量会显示类型(或直接显示值)的提示)
const myString = 'test'
// 类型断言(开发者明确知道是什么类型)
const someValue:any = 'abc'
const strLength:number = (someValue as string).length // 断言someValue是字符串类型
对象的类型
// 对象字面量的类型检查
const xiaojiejie: {
name: string,
age: number
} = {
name: '小红',
age: 18
}
// 标注:object
const obj:object = {}
// 使用接口
interface Person{
name: string
age: number
}
const xjj: Person = {
name: 'xh',
age: 18
}
// class类的类型检查
class Parson { }
const xiaobai: Parson = new Parson()
// 函数和返回值的类型检查
const fn: ()=> string = () => '123'
函数的类型注解
// 函数返回值的类型注解 fn(): number {}
function getTotal2(one: number, two: number): number {
return one + two
}
getTotal2(1,2)
// 无返回值: void
function sayHello(): void {
console.log("Hello")
}
// 永远执行不玩的函数
function setTimer():never {
throw new Error()
console.log(123)
}
// 参数是对象时的注解 (也可以用接口)
function add({ one, two }: {one: number, two: number}) {
return one + two
}
const total = add({one: 1, two: 2})
数组的类型注解
const numberArr: number[] = [1, 2, 3]
const stringArr: string[] = ['a', 'b']
const undefinedArr: undefined[] = [undefined, undefined]
const arr: (number | string | boolean)[] = [1, 'a', true, false] // 用到联合类型
// 类型别名 type alias
type lady = { name: string, age: number }
const xiaojj: lady[] = [
{
name: 'xiaojj',
age: 90
},
{
name: 'j',
age: 30
}
]
// 或用类的方式
class Ady2 {
name: string;
age: number;
}
const xiaojj2: Ady2[] = [
{
name: 'xiaojj',
age: 90
},
{
name: 'j',
age: 30
}
]
元组
元组,可以理解为:已知元素数量和类型的数组
// 联合类型
const xjj:(string | number)[] = ['a',22,'b'] // 规定整个数组当中可以有string或number
// 元组注解 注意这里的注解只有一个中括号
const xjj1: [string, number, number] = ['a', 22, 33] // 规定了数组每个元素对应位置的类型
// Note: 在开发中元祖的使用在相对少
// CSV的方式定义数据格式; (二维数组时需要多加一个中括号)
const xjj2: [string, number, number][] = [
['a', 22, 33],
['a', 22, 33]
]
接口
接口,可以理解为对象属性的类型描述。和类型别名
类似,不同的是 接口必须是一个对象,而别名可以直接是一个类型,如 type Girl = string
interface Girl { // 接口 (理解:对象属性的类型描述)
readonly name: string; // 只读属性 (定义之后不能再修改)
age: number;
waistline?: number; // 加个问号表示是可选值
[propname: string]: any; // 表示可以有不限制属性名的属性,但属性名需要是字符串,值可以是任意类型
say(): string; // 函数类型,返回值是string (如无返回值时是 void)。 say()也可以加入参数类型检查,如say(p:number)
}
// 和类型别名类似,不同的是 接口必须是一个对象,而别名可以直接是一个类型,如 type Girl = string
// 接口的继承
interface Teacher extends Girl {
teach(): string;
}
const girl = {
name: '大脚',
age: 18,
sex: '女',
say() {
return '欢迎光临'
},
teach() {
return '教'
}
}
const screenResume = ({ name, age, bust, sex }: Girl) => {
console.log(name, age, bust, sex)
}
const getResume = ({ name, age, bust, teach}: Teacher) => {
teach();
console.log(name, age, bust)
}
screenResume(girl)
getResume(girl)
// 接口在class类中的使用
class xiaojjj implements Girl {
name = "xiaojj"
age = 18
bust = 98
sex = '女'
say() {
return '欢迎光临'
}
}
可索引的类型
interface Arr {
[index: number]:string // 表示通过索引访问数据时返回的类型是string
}
const myArr:Arr = ['1','2','3']
const myStr:string = myArr[1]
ES6 class类中应用TS
class类的修饰器
// 类的修饰器:
// public (公共) 允许内外部使用
// protected (受保护的) 允许在内部和继承内使用
// private (私有) 允许在内部使用,但不能在继承中使用
// 类的内部和外部,{}内属于内部,外面是外部
class Person {
// public 内外都可以使用,可省略,不写时默认public。 protected只允许内部使用
name: string // 这里的string注释是TS使用的
private age: 18
public sayHello() {
console.log(this.name + this.age + 'say hello')
}
}
class Teacher2 extends Person {
public sayBye() {
console.log(this.name + ' say bye') // protected 可以在继承中使用到
}
}
const person = new Person();
person.name = 'test' // 在类的外部定义
console.log(person.name)
class类的构造函数中使用类型校验
class Person2 {
constructor(public name: string) {
this.name = name
}
}
class Teacher3 extends Person2{
constructor(public age: number) {
super('test-name') // 这里传的值是给Person2的构造函数。即使父类没有构造函数,子类的构造函数内也要写super()
}
}
const teacher3 = new Teacher3(18)
console.log(teacher3.name)
console.log(teacher3.age)
class类的getter、setter和static
class Xjj {
constructor(private _age: number) { }
get age() {
return this._age - 10;
} // 访问器属性,以属性的形式访问age,并可以对属性进行包装
set age(age: number) {
this._age = age+3;
}
}
const dj = new Xjj(28);
dj.age = 25
console.log(dj.age)
// 静态属性 static。 静态属性指不需要通过实例化,直接通过Girl.prop的方式就可以访问到属性
class Girl {
static sayLove() {
return 'I love you'
}
}
// const girl = new Girl()
console.log(Girl.sayLove())
class类的只读属性
// 只读属性
class Person {
public readonly _name: string // 只读属性
constructor(name: string) {
this._name = name;
}
}
const person = new Person('testName');
// person._name = '222'; // 不能修改只读属性
console.log(person._name)
抽象类
/ 抽象类
abstract class Girls {
abstract skill(); // 注意这里只是定义抽象方法,而不具有方法的实现
}
class Waiter extends Girls{ // 继承了抽象类之后要 实现抽象类内的成员
skill() {
console.log('大爷1')
}
}
class BaseTeacher extends Girls{
skill() {
console.log('大爷2')
}
}
class SeniorTeacher extends Girls{
skill() {
console.log('大爷3')
}
}
联合类型和类型保护
联合类型 指某个参数可以是多种类型。
类型保护 指参数属于某个类型才有相应的操作。
interface Waiter {
anjiao: boolean
say: () => {}
}
interface Teacher {
anjiao: boolean
skill: () => {}
}
function judgeWho(animal: (Waiter | Teacher)) { // 联合类型
// 第一种断言方法
if (animal.anjiao) {
// (animal as Teacher) 的意思是:断言 animal 是 Teacher类型
(animal as Teacher).skill()
} else {
(animal as Waiter).say()
}
// 第二种断言方法
if ('skill' in animal) {
animal.skill()
} else {
animal.say()
}
// 第三种类型保护方法是使用typeof来判断 (代码省略)
}
class NumberObj {
count: number
}
function addObj(first: object | NumberObj, second: object | NumberObj) { // 联合类型
if (first instanceof NumberObj && second instanceof NumberObj) { // 类型保护
return first.count + second.count;
}
return 0;
}
枚举
// Enum枚举类型 (个人理解枚举:约定一组可选的常量。 使用常量名表示某个值的含义,增强可读性。)
// js写法
// const Status = {
// MASSAGE: 0,
// SPA: 1,
// DABAOJIAN: 2
// }
// ts写法
enum Status {
MASSAGE, // 如果想从1开始,给MASSAGE = 1, 即可
SPA,
DABAOJIAN
} // 默认赋值 0 、1、2
console.log(Status.MASSAGE, Status[0]) // 0, MASSAGE 可以通过下标反查
function getStatus(status: any) {
if (status === Status.MASSAGE) {
return 'massage'
} else if (status === Status.SPA) {
return 'spa'
} else if (status === Status.DABAOJIAN) {
return 'dabaojian'
}
}
const result = getStatus(Status.SPA)
console.log(result)
泛型
泛型,最简单的理解:泛指的类型。(类似函数中的形参与实参)
函数中的泛型使用
// function join(first: string | number, second: string | number) {
// return `${first}${second}`
// }
// join('jspang', 1); // 如果我想第一个参数是字符串,第二个也必须是字符串,这么就用到泛型
// 泛型使用,如同定义形参,在调用时指定类型
function join<JSPang>(first: JSPang, second: JSPang) {
return `${first}${second}`
}
join<string>('jspang', '123');
join<number>(11, 22);
// 泛型中数组的使用
function myFun<ANY>(params:ANY[]) { // ANY[] or Array<ANY>
return params
}
myFun<string>(['a', 'b'])
// 两个类型参数的使用(工作中,常用T表示泛型)
function join2<T,P>(first: T, second: P) {
return `${first}${second}`
}
join2<string,number>('jspang', 123);
join2<number, string>(11, '22');
join2(11, '22'); // 泛型也支持类型推断 (鼠标移到函数名有提示)
class类中使用泛型
// class SelectGirl {
// constructor(private girls: string[] | number[]) { } // private 私有的参数,外部无法修改
// getGirl(index: number): string | number {
// return this.girls[index]
// }
// }
// 使用泛型
class SelectGirl<T> { // 泛型的约束: <T extends number | string>
constructor(private girls: T[]) { } // private 私有的参数,外部无法修改
getGirl(index: number): T {
return this.girls[index]
}
}
// const selectGirl = new SelectGirl<string>(['大脚', 'xiaohong', 'xiaobai'])
const selectGirl = new SelectGirl<number>([101, 102, 103])
console.log(selectGirl.getGirl(1))
// 泛型中的继承
interface Girl {
name: string
}
class SelectGirl2<T extends Girl> { // 泛型T中必须有一个name属性,继承自Girl接口
constructor(private girls: T[]) { } // private 私有的参数,外部无法修改
getGirl(index: number): string {
return this.girls[index].name
}
}
const selectGirl2 = new SelectGirl2([
{name: '大脚1'},
{name: '大脚2'},
{name: '大脚3'}
])
console.log(selectGirl2.getGirl(1))
配置文件tsconfig.json
// 此文件由命令 tsc -init 生成
// 直接运行 tsc 命令就会运用此配置文件
// 选项详解:https://www.tslang.cn/docs/handbook/compiler-options.html
{
// "include": ["demo15-1.ts"], // 要编译的指定文件,不配置此项时运行tsc默认编译全部
// "files": ["demo15-1.ts"], // 和include类似
// "exclude": ["demo15-3.ts"], // 要排除编译的指定文件
"compilerOptions": { // 编译选项
/* 基本选项 */
// "incremental": true, /* Enable incremental compilation */
"target": "es5", /* 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
"module": "commonjs", /* 指定模块代码生成: '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. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
"sourceMap": true, /* 源文件与输出文件的映射关系文件。Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./build", /* 输出的js文件目录。Redirect output structure to the directory. */
"rootDir": "./src", /* ts源文件目录。Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* 不输出注释到编译结果. */
// "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'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* 严格的类型检查选项 */
"strict": true, /* 启用所有严格类型检查选项。 打开此选项后,下面这些选项就不需要单独设置*/
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. 为false时允许any不用特意声明。*/
// "strictNullChecks": true, /* Enable strict null checks. 为false时允许赋值为null*/
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* 附加检查。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. */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "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. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
}
}