持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情
什么是Ts
Typed JavaScript at Any Scale. 具有类型的JavaScript,适用于任何大小的项目。 我们可以理解为ts是用来hook js的,就是在js编译时判断类型,编译后和原本js代码完全相同
// hellow.ts
function test(name: string) {
return 'Hello, ' + name;
}
console.log(sayHello('Tom'));
tsc hello.ts后实际代码和原本js完全相同
function test(name) {
return 'Hello, ' + name;
}
console.log(sayHello('Tom'));
假如非string类型参数
sayHello(123)时候 上面代码直接报错, 下面代码则运行正常。
ts和js同属于弱类型语言(即会自动帮我们转化类型后计算,而不是开发者显示的写出转换代码) 所以ts会编译时校验类型,规避错误,js则不会,如遇到报错则会在运行时抛出, 其他非错误的异常显示情况则需要开发者自行检查判断。
优点
- 节省了很多判断异常的类型校验代码。
- 将错误信息从运行时提前到编译时抛出。
相同代码.ts会在编译时抛错,.js则是运行过后才抛错。所以ts将错误提前暴露
let a = 1
a.split(' ')
为了规范,便于阅读通常 TypeScript 编写的文件以 .ts 为后缀, React项目pages页面,则以 .tsx 为后缀。
类型定义
基本类型
变量名称: 变量类型 内置8种类型
string number boolean undefined null object bigint symbol
let str: string = "jimmy";
注意 null 和 undefined 是所有类型的子类型
数组
type[] 来表示数组
类型type用来定义Shape(里面元素的类型)的, [] 也就是数组
let numberArray: number[] = [1,2,3,4,5]
numberArray.push('8'); // 报错,必须传push进去number的元素
ts同时也支持和java保持一致的泛型,这种更加通俗易懂
let numberArray: Array<number> = [1, 1, 2, 3, 5];
问题: 假如我想不同index不同类型的数组如何定义。
元祖
元祖可以定义数组中不同位置的类型。缺点是必须限定数组个数
// 相当于 let employee = [1, "Semlinker"]
let employee: [number, string] = [1, "Semlinker"];
// 结构也必须参数个数一致
let [id, username] = employee;
// let [id, username, age] = employee; // error
// 问号`?`表示参数可选
type Point = [number, number?, number?];
//以下三种方式定义Point类型变量都合法
// const x: Point = [10];
// const x: Point = [10,10];
const x: Point = [10,10,10];
// readonly 类型的同样后面不可改变数组的值了
const point: readonly [number, number] = [10, 20];
let x: [string, number];
对象类型,接口
java里面接口定义可以完全忽略,这里我们理解成为interface就是限定对象Shape形状(里面元素类型)的
interface Person {
readonly id: number;
name: string; // 确定(类型)属性,name
age: number;
id?: number; // 可选属性
[propName: string]: any; // 任意属性
}
let tom: Person = {
id: 123,
name: 'Tom',
age: 25
};
tom.id = 9527; // 会报错,因为定义的是只读属性
接口interface中定义的确定属性。 ----interface的定义 在定义接口属性的变量的时候 ---- let tom:Interface = {}
- 所有的确定属性都必须赋值
- 可选属性可以赋值也可以不赋值
- 如果有任意属性,则其他所有属性的类型都必须是任意属性中包含的
函数
// 函数声明
function funcName1(x, y) {
}
// 函数表达式
let funcName2 = function (x, y) {
}
分别定义如下
function funcName1(x:number, y:number): number {
return x + y
}
// rest为剩余参数数组,剩余参数的类型可以为任意类型
let funcName2: (x: number, y: number, ...rest: any[]) => number = function (x: number, y: number): number {
return x + y;
};
如下定义,
- 可以给确定类型的参数赋值默认值。
- parameter?:type 定义可选参数parameter,类型为type,可选参数必须在末尾定义(确定类型参数后面定义)。
function funcName1(x:number, y:number = 1, z?:string): number {
return x + y
}
重载
同样是java的概念,即相同名称,不同参数类型,不同参数数量,就视为不同函数
例子: 数字和字符串翻转我们可以这样定义、 123 变 321 hellow 变 wolleh
function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string | void {
if (typeof x === 'number') {
return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
return x.split('').reverse().join('');
}
}
类型推论
在没有指定类型的时候ts会根据赋值情况推测出一个类型来。 触发类型推论的条件:声明的时候同时赋值了。
let name = 'jack' // 类型推论会认为name为string类型
name = 1001 // 所以会报错
any类型
可以为任意类型,即不校验类型
- 明确指定any类型
- 生命的时候不赋值 以上两点满足则为any类型
// 1.指定类型
let name: any = 'jack'
name = 10001
或者
// 2.声明不赋值
let name2
name2 = 'jack'
name2 = 10001
联合类型
即可以为多个类型中的任意一个类型 联合类型使用|分隔每个类型。
let name: string | number;
作为变量传递的时候,需手动判断是否可以用该类型api 赋值的时候,会根据类型指定,自动判断类型
赋值的时候类型确定的可以类型指定
let name: string | number;
name = 'jack'
console.log(name.length)
name = 7
console.log(name.length) // TS2339: Property 'length' does not exist on type 'number'.
作为变量的时候,不确定,需要自己判断
function getFullName(name: string | number) {
// 如果那么传进来的是number就会报错
// TS2339: Property 'length' does not exist on type 'number'.
return name.length > 0 ? name : ''
}