文章内容输出来源:拉勾教育大前度高薪训练营
typeScript:javaScript的超集(superet)
typeScript 概述
- 所谓超级是指:一套更加强大的类型系统,和对es6新特性的支持, 最终会编译成javaScript;
- 作用:帮我们避免编码中出现的类型异常,提高我们编码的效率以及我们代码的可靠程度;
- 兼容性:最低可编译到es3版本, 兼容性较好;
- 任何一种JavaScript运行环境都支持;
- 相较于folw,typeScript功能更为强大,生态也更健全、更完善;
- 目前angular/vue3已经开始使用typeScript;
- 你会发现typeScript慢慢的将成为前端领域中的第二语言;
- 缺点:
1. 语法本身多了很多概念(typescript属于「渐进式」的);
2. 项目初期,typeScript会增加一些成本;
typeScript快速上手
-
安装:
- 初始化package.json -- 命令:yarn init -y
{ "name": "typeScript",
"version": "1.0.0",
"main": "index.js",
"license": "MIT"
}- 安装开发依赖:yarn add typescript -D
{ "name": "typescript",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"devDependencies": {
"typescript": "^4.1.3"
}
}- tsc的作用:用于编译typescript
- 可以完全按照JavaScript标准语法编译代码
-
代码示例:
-
编译前:
const hello = name => { console.log(`hello ${name}`);
}
hello('typeScript'); -
编译后:
var hello = function (name) { console.log("hello " + name);
};
hello('typeScript');
-
-
ts初使用:
const hello = (name: string) => { console.log(`hello ${name}`);
}
// hello('typeScript');
hello(100);
typeScript配置文件
- 创建typescript配置文件:yarn tsc --init
- 使用tsconfig编译ts文件:yarn tsc
{ "compilerOptions": {
/* 访问https://aka.ms/tsconfig.json以了解有关此文件的更多信息 */
/* 基本选项 */
// "incremental": true, /* 启用增量编译 */
"target": "es5", /* 指定ECMAScript目标版本:``ES3''(默认),``ES5'',``ES2015'',``ES2016'',``ES2017'',``ES2018'',``ES2019'',``ES2020''或``ESNEXT''。 */
"module": "commonjs", /* 指定模块代码生成:“ none”,“ commonjs”,“ amd”,“ system”,“ umd”,“ es2015”,“ es2020”或“ ESNext”。 */
// "lib": [], /* 指定要包含在编译中的库文件 */
// "allowJs": true, /* 允许编译javascript文件。 */
// "checkJs": true, /* 报告.js文件中的错误。 */
// "jsx": "preserve", /* 指定JSX代码生成:'preserve''react-native'或'react'。 */
// "declaration": true, /* 生成相应的'.d.ts'文件。 */
// "declarationMap": true, /* 为每个相应的'.d.ts'文件生成一个源映射。*/
// "sourceMap": true, /* 生成相应的'.map'文件。*/
// "outFile": "./", /* 连接并输出到单个文件。*/
// "outDir": "./", /* 将输出结构重定向到目录。 */
// "rootDir": "./", /* 指定输入文件的根目录。用于通过--outDir控制输出目录结构。 */
// "composite": true, /* 启用项目编译 */
// "tsBuildInfoFile": "./", /* S指定用于存储增量编译信息的文件 */
// "removeComments": true, /* 不输出注释。 */
// "noEmit": true, /* 不发出输出。 */
// "importHelpers": true, /* 从'tslib'导入导入发射助手。*/
// "downlevelIteration": true, /* 在以'ES5'或'ES3'为目标时,以'for-of',散布和解构形式提供对Iterables的全面支持。*/
// "isolatedModules": true, /* 将每个文件作为单独的模块进行编译(类似于'ts.transpileModule')。 */
/* 严格的类型检查选项 */
"strict": true, /* 启用所有严格的类型检查选项。 */
// "noImplicitAny": true, /* 在隐式“ any”类型的表达式和声明上引发错误。 */
// "strictNullChecks": true, /* 启用严格的null检查。*/
// "strictFunctionTypes": true, /* 启用对函数类型的严格检查*/
// "strictBindCallApply": true, /* 在函数上启用严格的“ bind”,“ call”和“ apply”方法。 */
// "strictPropertyInitialization": true, /* 在类中启用对属性初始化的严格检查。 */
// "noImplicitThis": true, /* 在隐含'any'类型的'this'表达式上引发错误。 */
// "alwaysStrict": true, /* 以严格模式解析,并对每个源文件发出“ use strict”。 */
/* 其他检查*/
// "noUnusedLocals": true, /* 报告未使用的本地错误。 */
// "noUnusedParameters": true, /* 报告未使用参数的错误。 */
// "noImplicitReturns": true, /* 当并非函数中的所有代码路径都返回值时,报告错误。 */
// "noFallthroughCasesInSwitch": true, /* 在switch语句中报告失败情况的错误。 */
// "noUncheckedIndexedAccess": true, /* 在索引签名结果中包括“ undefined” */
/* 模块分辨率选项*/
// "moduleResolution": "node", /* 指定模块解析策略:'node'(Node.js)或'classic'(TypeScript 1.6之前的版本)。*/
// "baseUrl": "./", /* 用于解析非绝对模块名称的基目录。*/
// "paths": {}, /* 一系列条目,这些条目将导入重新映射到相对于'baseUrl'的查找位置。 */
// "rootDirs": [], /* 根目录列表,其组合内容表示运行时项目的结构。*/
// "typeRoots": [], /* 要包括其类型定义的文件夹列表。 */
// "types": [], /* 要包含在编译中的类型声明文件。 */
// "allowSyntheticDefaultImports": true, /* 允许从默认导入模块,而没有默认导出。这不影响代码发出,仅影响类型检查。 */
"esModuleInterop": true, /* 通过为所有导入创建名称空间对象来启用CommonJS和ES模块之间的发射互操作性。暗示“ allowSyntheticDefaultImports”。 */
// "preserveSymlinks": true, /* 不解析符号链接的真实路径。 */
// "allowUmdGlobalAccess": true, /* 允许从模块访问UMD全局变量。 */
/* 源映射选项 */
// "sourceRoot": "", /* 指定调试器应在其中定位TypeScript文件的位置,而不是源位置。 */
// "mapRoot": "", /* 指定调试器应定位地图文件的位置,而不是生成的位置。 */
// "inlineSourceMap": true, /* 发出带有源映射的单个文件,而不是单独的文件。 */
// "inlineSources": true, /* 在单个文件中将源代码与源映射一起发射出去;需要设置“ --inlineSourceMap”或“ --sourceMap”。*/
/* 实验选项 */
// "experimentalDecorators": true, /* 启用对ES7装饰器的实验性支持。 */
// "emitDecoratorMetadata": true, /* 启用实验性支持以发出装饰器的类型元数据。 */
/* 高级选项 */
"skipLibCheck": true, /* 跳过声明文件的类型检查。 */
"forceConsistentCasingInFileNames": true /* 禁止对同一文件使用大小写不一致的引用。 */
}
}
原始类型:Primitive Types
/**
* 原始数据类型
*/
const a: string = "foobar";
const b: number = 100 // NaN Infinity
const c: boolean = true // false
// const d: boolean = null // 严格模式下string/boolean/number不允许为空
const e: void = undefined // null // 严格模式下只能是undefined
const f: null = null
const g: undefined = undefined;
typeScript标准库声明
- Symbol()为es6新增
- 使用方法:
- 第一种:修改"target"为 "es2015"
- 第二种:添加"lib": [ "ES2015","DOM" ]
/**
* Symbol()为es6新增
*/
const h: symbol = Symbol();
- 标准库就是内置对象所对应的声明
typeScript中文错误信息
第一种方法:yarn tsc --locale zh-CN
第二种方法:
typeScript 作用域问题
// 作用域问题
const a = 123; // 无法重新声明块范围变量“a”。报错原因:全局作用上已经有a变量
/**
* 解决方法1:将变量放到立即执行函数当中
*/
(function () {
const a = 123;
})()
/**
* 解决方法2:以模块的方式使用
*/
const a = 123;
export { }
typeScript Object类型
// object 类型
export { } // 确保跟其他示例没有成员冲突
const foo: object = function () { } //[] //{}
const obj: { foo: number, bar: string } = { foo: 11, bar: 'string' }
typeScript数组类型
// 数组类型
export { } // 确保跟其他示例没有成员冲突
const arr1: Array<number> = [12, 23, 4];
const arr2: number[] = [1, 2, 3];
//--------------
function sum(...args: number[]) {
return args.reduce((prev, current) => prev + current, 0)
}
sum(1, 2, 3)
元组类型 Tuple Types
- 数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象。
- 元组起源于函数编程语言(如 F#),这些语言中会频繁使用元组。
// 元组 Tuple
export { } // 确保跟其他示例没有成员冲突
const tuple: [number, string] = [12, 'zce'];
// const age = tuple[0];
// const name = tuple[1];
const [age, name] = tuple;// 数组解构的方式获取值
// ----------
Object.entries({
foo: 123,
bar: '34'
})
typeScript 枚举类型
- 枚举(Enum)类型用于取值被限定在一定范围内的场景,比如一周只能有七天,颜色限定为红绿蓝等。
// 枚举 Enum
export { } // 确保跟其他示例没有成员冲突
// const PostStatus = {
// Draft: 0,
// Unpublished: 1,
// Published: 2
// }
// 自动添加值
// enum PostStatus {
// Draft = 0,
// Unpublished = 1,
// published = 2
// }
// 默认值 0 1 2
// enum PostStatus {
// Draft,
// Unpublished,
// published
// }
// 从第一个开始自增
// enum PostStatus {
// Draft = 5,
// Unpublished,
// published
// }
// 值为字符串
// enum PostStatus {
// Draft = "aaa",
// Unpublished = "bbb",
// published = "ccc"
// }
const enum PostStatus {
Draft,
Unpublished,
published
}
const post = {
title: "Hello TypeScript",
content: "TypeScript is a typed superset of JavaScript",
status: PostStatus.Draft
}
TypeScript 函数类型
// 函数类型
export {}; // 确保跟其他示例没有成员冲突
// function func1(a: number, b: number): string {
// return 'func1';
// }
// func1(100, 200);
// func1(100);
// func1(100, 200, 300);
// 参数可选
// function func1(a: number, b?: number): string {
// return 'func1';
// }
// func1(100, 200);
// func1(100);
// func1(100, 200, 300);
// 默认参数s
// function func1(a: number, b: number = 200): string {
// return 'func1';
// }
// func1(100, 200);
// func1(100);
// func1(100, 200, 300);
// 默认参数
// function func1(a: number, b: number = 200): string {
// return 'func1';
// }
// func1(100, 200);
// func1(100);
// func1(100, 200, 300);
// 任意参数
// function func1(a: number, b: number = 200, ...rest: number[]): string {
// return 'func1';
// }
// func1(100, 200);
// func1(100);
// func1(100, 200, 300);
// 函数表达式所对应的限制
const func2: (a: number, b: number) => string = function (
a: number,
b: number
): string {
return 'func2';
};
TypeScript 任意类型
// 任意类型
export {}; // 确保跟其他示例没有成员冲突
function stringfy(value: any) {
return JSON.stringify(value);
}
stringfy('string');
stringfy(100);
stringfy(true);
let foo: any = 'string';
foo = 100;
foo.bar();
// any类型是不安全的
TypeScript 隐式类型推断
// 隐式类型推断
/**
* Age => 年龄
* let age: number
* 不能将类型“string”分配给类型“number”。
*/
let age = 18;
// age = 'string';
类型断言
// 类型断言
export {}; // 确保跟其他示例没有成员冲突
// 假定这个nums 来自一个明确的接口
const nums = [110, 120, 119, 112];
const res = nums.find((i) => i > 0);
// const square = res * res;
const num1 = res as number; // 断言as
const num2 = <number>res; // 断言<number> JSX下不能使用
TypeScript 接口
// 接口
export {}; // 确保跟其他示例没有成员冲突
// 接口定义
// interface Post {
// title: string;
// content: string;
// }
// function printPost(post: Post) {
// console.log(post.title);
// console.log(post.content);
// }
// printPost({ title: '111', content: '2222' });
// ----------
interface Post {
title: string;
content: string;
subtitle?: string; // 可选
readonly summary: string; // 只读
}
const hello: Post = {
title: "Hello TypeScript",
content: "a JavaScript Supperset",
summary: "a JavaScript",
};
// ------------
interface Cache {
[prop: string]: string;
}
const cache: Cache = {};
cache.value = "value";
cache.foo = "foo";
TypeScript 类的基本使用
- 描述一类具体事物的抽象特征,例如:手机
- 用来描述一类具体对象的抽象成员
- ES6以前, 都是通过函数+原型模拟实现类
- ES6开始,Javascript中有了专门的class
- TypeScript增强了class的相关语法
// 类 class
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
sayHi(msg: string): void {
console.log("I am ${this.name},${this.age}");
}
}
TypeScript 类的访问修饰符
// 类的访问修饰符
export {};
class Person {
public name: string;
private age: number;
protected gender: boolean;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
this.gender = true;
}
sayHi(msg: string): void {
console.log("I am ${this.name},${this.age}");
}
}
class Student extends Person {
private constructor(name: string, age: number) {
super(name, age);
console.log(this.gender);
}
static create(name: string, age: number) {
return new Student(name, age);
}
}
const tom = new Person("tom", 18);
console.log(tom.name);
// console.log(tom.age);// age为私有成员
// console.log(tom.gender);
// const jack = new Student(); // private只允许在内部使用
const jack = Student.create("jack", 18); // 通过static访问
TypeScript 类的只读属性
// 只读属性 readonly
export {};
class Person {
public name: string;
private age: number;
protected readonly gender: boolean;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
this.gender = true;
}
sayHi(msg: string): void {
console.log("I am ${this.name},${this.age}");
}
}
const tom = new Person("tom", 18);
console.log(tom.name);
// tom.gender = false;
TypeScript 类与接口
// 类与接口
export {};
// interface EatAndRun {
// eat(food: string): void;
// run(distance: number): void;
// }
// class Person implements EatAndRun {
// eat(food: string): void {
// console.log(`优雅的进餐:${food}`);
// }
// run(distance: number) {
// console.log(`直立行走:${distance}`);
// }
// }
// class Animal implements EatAndRun {
// eat(food: string): void {
// console.log(`呼噜呼噜的吃:${food}`);
// }
// run(distance: number) {
// console.log(`爬行:${distance}`);
// }
// }
// --------------
interface Eat {
eat(food: string): void;
}
interface Run {
run(distance: number): void;
}
class Person implements Eat, Run {
eat(food: string): void {
console.log(`优雅的进餐:${food}`);
}
run(distance: number) {
console.log(`直立行走:${distance}`);
}
}
class Animal implements Eat, Run {
eat(food: string): void {
console.log(`呼噜呼噜的吃:${food}`);
}
run(distance: number) {
console.log(`爬行:${distance}`);
}
}
TypeScript 抽象类
// 抽象类
export {};
abstract class Animal {
eat(food: string): void {
console.log(`呼噜呼噜的吃:${food}`);
}
abstract run(distance: number): void;
}
class Dog extends Animal {
run(distance: number): void {
throw new Error("Method not implemented.");
}
}
const d = new Dog();
d.eat("的说法");
d.run(100);
TypeScript 泛型
//泛型
export {};
function createNumberArray(length: number, value: number): number[] {
const arr = Array<number>(length).fill(value);
return arr;
}
function createStringArray(length: number, value: string): string[] {
const arr = Array<string>(length).fill(value);
return arr;
}
function createArray<T>(length: number, value: T): T[] {
const arr = Array<T>(length).fill(value);
return arr;
}
// const res = createNumberArray(3, 100); //res => [100,100,100]
const res = createArray<string>(2, "foo");
TypeScript 类型声明
// 类型声明
import { camelCase } from "lodash";
import qs from "query-string";
qs.parse("?key=value&key2=value2");
// declare function camelCase(input: string): string;
const res = camelCase("hello Typed");