前言
众所周知,javascript是一门弱类型的语言,它不会限制参数的类型,允许任意的数据类型转换。而typescript是强类型语言,是Javascript的超集,最后会被编译成Javascript。
优点
- 错误更早暴露
- 代码更智能,编码更准确,开发工具的智能提示
- 重构更牢靠
- 减少不必要的类型判断
- 渐进式
作用域
如果全局有重复定义的str参数,ts会报错
Cannot redeclare block-scoped variable 'str'.
解决方案有两种:
- 立即执行函数
(function(){
})();
- ESM
// b.ts
const str: number = 123;
export { str };
//又或者直接使用
export {} //确保跟其他实例没有成员冲突;
原始类型
- string 字符串
- number 数字类型 包括NaN ,Infinity
- boolean 布尔类型
- void
- null
- undefined
- symbol(新类型,target必须要es2015)
非严格模式下,string,number,boolean三个基础类型可以为null或者undefined
// tsconfig.json 配置方法:
"strict" : true, //用于指定是否启动所有类型检查,如果设为true会同时开启下面这几个严格检查,默认为false
"strictNullChecks": true //当设为true时,null和undefined值不能赋值给非这两种类型的值,别的类型的值也不能赋给他们,除了any类型,还有个例外就是undefined可以赋值给void类型
非原始类型
- object
const foo : object = function(){} //这个指的是除了原始类型以外的类型
//也可以用这种字面量的定义
const obj: { name: string; age: number } = {
name: "ronald",
age: 18,
};
- array数组类型
const arr1: Array<number> = [1, 2, 3, 4];
const arr2: number[] = [1, 2, 3];
function sum(...args: number[]) {
return args.reduce((prev, current) => {
return prev + current;
}, 0);
}
//sum(1, 2, 3, "aaa"); //报错
sum(1,2,3,4)
let list : Array<number> = [1,2,3,4,5]; //泛型的写法
- 元组类型(tuple)
元组中允许存储不同类型的元素,元组可以作为参数传递给函数。
export {};
const tuple: [number, string] = [18, "ronald"];
// const age = tuple[0];
// const name = tuple[1];
const [age, name] = tuple; //元组解构
var mytuple = [10, "Runoob", "Taobao", "Google"]; // 创建一个元组
console.log("元组的第一个元素为:" + mytuple[0]);
// 更新元组元素
mytuple[0] = 121;
console.log("元组中的第一个元素更新为:" + mytuple[0]);
- 枚举类型
export {};
//枚举值一般由0开始,如果中途定义了值,则下一个值以上一个值为准累加
enum PopStatus {
draft,
unFinished = 5,
Finished,
Over,
}
console.log(PopStatus.Finished); //6
//如果想定义枚举字符串,则需要每个值都要定义,因为字符串不能自增
enum RoleStatus {
manager = '经理',
rookie = '菜鸟'
}
console.log(RoleStatus.manager)
- 函数类型(Function Types)
function func1(a: string, b: number, ...rest: number[]): string {
return "func1";
}
func1("ronald", 18 );
//如果是对象里的方法,可以这么定义
interface aa {
say: (name: string, age: number) => string;
}
let obj: aa = {
say: (name, age) => {
return name + age;
},
};
console.log(obj.say("ronald", 12));
- 任意类型any
let str:any = 112; //赋值任意类型都可以,不做检查
function stringify(value : any) : any{
return JSON.stringify(value);
}
类型推断
数据没有指定明确的类型,那么ts会按照类型推论的规则推断出一个类型
let myFavoriteNumber = 'seven';
myFavoriteNumber = 7; ////被推断成字符串了,不在能被赋值给数值型数据了
//myFavoriteNumber
// index.ts(2,1): error TS2322: Type 'number' is not assignable to type 'string'.
类型断言
类型断言可以用来手动指定一个值得类型,
语法:使用as关键字或者<类型>值
值 as 类型
<类型>值
const nums = [1,2,3,4,5];
const res = nums.find(i=> i>3)
const nums1 = res as number;
const nums2 = <number>res;
接口(Interface)
接口(Interfaces)可以用来定义对象的类型,它是对行为的抽象,除了可用于对类的一部分行为进行抽象以外,也常用于对「对象的形状(Shape)」进行描述。
注意: 接口一般首字母大写,建议在接口名称前面加上I前缀区分
interface IPerson{
name : string;
age : number;
class?: string; //可选成员
readonly hobby : string; //只读
}
let p1:IPerson = {
name : 'ronald',
age : 18,
hobby : '打篮球'
}
p1.hobby = '唱,跳'; //无法分配到 "hobby" ,因为它是只读属性
//限定参数传入格式
function getPersonInfo(person: IPerson) {
console.log(person.name);
console.log(person.age);
}
getPersonInfo({ age: 18, name: "ronald", hobby: "打篮球" });
如果在定义过程中无法确定里面的成员名称,可以用下面这些写法
interface ICache {
//成员的键值为string类型,属性为string或者number类型
[prop: string]: string | number;
}
const cache:ICache = {}
cache.foo = 'value1';
cache.bar = 'bar';
类
可以用于描述一类具体对象的抽象成员
class Person{
public name : string //公有属性,内外都可使用
private age : number //私有属性,只能在类内部访问
protected gender : boolen //保护属性,只能在类和子类里使用,不能被派生类使用
readonly hobby : string //只读,不可修改
constructor(name :string,age:number){
this.name = name;
this.age = age;
}
sayHi(msg : string):void{
console.log(`IM ${this.name},${msg}`)
}
}
const tom = new Person('ronald',18);
console.log(tom.age); //报错,私有属性
抽象类
抽象类只能被继承,不可以被实例化
abstract class Animal {
eat(food: string): void {
console.log("我在吃" + food);
}
abstract run(distance: number): void;
}
class Dog extends Animal {
run(distance: number): void {
console.log("我是小狗,跑了" + distance);
}
}
const dog = new Dog();
dog.run(5000);
泛型
为了考虑复用性,通过我们使用泛型去定义可重用的组件,允许同一个函数接受不同类型的参数
- 泛型接口
interface GenericIdentityFn<T> {
(arg: T): T;
}
- 泛型类
class GenericNumber<T> {
value: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.value = 0;
myGenericNumber.add = function (x, y) {
return x + y;
};
- 泛型变量
常见的泛型变量
-
T(Type):表示一个 TypeScript 类型
-
K(Key):表示对象中的键类型
-
V(Value):表示对象中的值类型
-
E(Element):表示元素类型
类型声明模块
如果引入了外部插件但又没对模块进行声明的话,ts会报错,现在大部分的插件都会有对应的类型声明,引入即可
// 尝试使用 npm i --save-dev @types/lodash
(如果存在),或者添加一个包含 declare module 'lodash';
的新声明
import {camelCase} from 'lodash';
//手动定义
declare function camelCase(input : string) string
//或者引入@types/lodash
const res = camelCase('hello typed');
tsconfig.json配置
配置文件里面有4个重要的字段:
- files - 编译的文件的名称;
- include - 需要编译的文件,支持路径模式匹配;
- exclude - 无需编译的文件,支持路径模式匹配;
- compilerOptions - 与编译流程相关的选项。
{
"compilerOptions": {
/* 基本选项 */
"target": "es5", // 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES6'/'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'
"module": "commonjs", // 指定使用模块: 'commonjs', 'amd', 'system', 'umd' or 'es2015'
"lib": [], // 指定要包含在编译中的库文件
"allowJs": true, // 允许编译 javascript 文件
"checkJs": true, // 报告 javascript 文件中的错误
"jsx": "preserve", // 指定 jsx 代码的生成: 'preserve', 'react-native', or 'react'
"declaration": true, // 生成相应的 '.d.ts' 文件
"sourceMap": true, // 生成相应的 '.map' 文件
"outFile": "./", // 将输出文件合并为一个文件
"outDir": "./", // 指定输出目录
"rootDir": "./", // 用来控制输出目录结构 --outDir.
"removeComments": true, // 删除编译后的所有的注释
"noEmit": true, // 不生成输出文件
"importHelpers": true, // 从 tslib 导入辅助工具函数
"isolatedModules": true, // 将每个文件做为单独的模块 (与 'ts.transpileModule' 类似).
/* 严格的类型检查选项 */
"strict": true, // 启用所有严格类型检查选项
"noImplicitAny": true, // 在表达式和声明上有隐含的 any类型时报错
"strictNullChecks": true, // 启用严格的 null 检查
"noImplicitThis": true, // 当 this 表达式值为 any 类型的时候,生成一个错误
"alwaysStrict": true, // 以严格模式检查每个模块,并在每个文件里加入 'use strict'
/* 额外的检查 */
"noUnusedLocals": true, // 有未使用的变量时,抛出错误
"noUnusedParameters": true, // 有未使用的参数时,抛出错误
"noImplicitReturns": true, // 并不是所有函数里的代码都有返回值时,抛出错误
"noFallthroughCasesInSwitch": true, // 报告 switch 语句的 fallthrough 错误。(即,不允许 switch 的 case 语句贯穿)
/* 模块解析选项 */
"moduleResolution": "node", // 选择模块解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6)
"baseUrl": "./", // 用于解析非相对模块名称的基目录
"paths": {}, // 模块名到基于 baseUrl 的路径映射的列表
"rootDirs": [], // 根文件夹列表,其组合内容表示项目运行时的结构内容
"typeRoots": [], // 包含类型声明的文件列表
"types": [], // 需要包含的类型声明文件名列表
"allowSyntheticDefaultImports": true, // 允许从没有设置默认导出的模块中默认导入。
/* Source Map Options */
"sourceRoot": "./", // 指定调试器应该找到 TypeScript 文件而不是源文件的位置
"mapRoot": "./", // 指定调试器应该找到映射文件而不是生成文件的位置
"inlineSourceMap": true, // 生成单个 soucemaps 文件,而不是将 sourcemaps 生成不同的文件
"inlineSources": true, // 将代码与 sourcemaps 生成到一个文件中,要求同时设置了 --inlineSourceMap 或 --sourceMap 属性
/* 其他选项 */
"experimentalDecorators": true, // 启用装饰器
"emitDecoratorMetadata": true // 为装饰器提供元数据的支持
}
}
开启中文提示
打开终端输入以下命令即可开启:
tsc -w --locale zh-CN
建议不开,通常我们遇到错误需要google的时候一般都是直接英文搜索