为什么需要TypeScript?
TypeScript主要是用于静态类型的检查。使用JS的时候,我们必须要知道各种类型的细节才可以编写正确的代码。
Ts文件和JS文件同时存在出现函数重复问题
解决上述问题只需要初始化typescript的配置文件即可。
tsc --init
关闭TS的检查
只需将ts的配置文件中的strict这一行注释掉即可。
持续将TS转换为JS
tsc --watch
显示类型
function test2(person: string,date: Date) {
console.log(`${person}你好,今天是:${date.toDateString()}`);
}
test2('张三',new Date())
常用类型
- 基元类型(string,number,boolean)
let str: string = "张三";
let num: number = 20;
let bool: boolean = false;
- 数组(type[] 或者 Array[type])
let nums: Array= [1,2,3];
let nums1: number[] = [4,5,6];
- any(不希望某个特定的值导致类型检查错误)
let obj: any = {
x: '666'
}
// 下面的这句TS不会报错,但是转换为JS后是不能正常运行的,但是定义为any后可以防止报错
obj.foo()
- 函数(主要是对参数和返回值进行注解)
function greet(name: string): void {
console.log('Hello' + name);
}
- 对象类型
function printxy(pt: {x: number, y: number}) {
console.log(pt.x,pt.y);
}
printxy({x: 25,y: 26})
- 联合类型
let test: number | string = 20;
let test2: numer | string | number[] = 21;
test = '111'
- 类型别名
type Point = {
x: number,
y: number
}
function test(param: Point) {
console.log(param.x,param.y);
}
- 接口
interface Point {
x: number;
y: number;
}
function test(pt: Point) {
console.log(pt.x,pt.y);
}
test({x: 2,y: 10})
类型别名type和接口interface的区别是什么?
- 拓展方法不同
//使用interface来拓展接口
interface Animal {
name: string;
}
interface Bear extends Animal {
hobby: string;
}
const bear: Bear = {
name: '熊',
hobby: '蜂蜜'
}
// 下面是使用type来拓展类型
type Animal = {
name: string
}
type Bear = Animal & {
hobby: string
}
const bear: Bear = {
name: "熊",
hobby: '吃蜂蜜'
}
- 同名interface会合并不会覆盖,但是同名type是会报错的。
interface Bear {
name: string;
}
interface Bear {
age: number;
}
const bear: Bear = {
name: '熊',
age: 20
}
类型断言
类型断言的意义是告诉编译器这个变量是这种类型的,下面是两种定义方法,分别是as和尖括号语法。
// 类型断言
const myCanvas = document.getElementById('main_canvas') as HTMLCanvasElement;
const myCanvas2 =document.getElementById('main_canvas');
文字类型
文字类型可以指定文字的一些选项。
function test(s: string,align: 'left' | 'right' | 'center') {
console.log(s,align);
}
test('张三','left')
断言一定存在和可选参数
function test(name?: string | string[]) {
console.log(name!.toString());
}
枚举
枚举类型会自动进行递增。
enum Direction {
up = 1,
left,
right,
down
}
console.log(Direction.down); // 4
类型缩小
类型缩小就是将宽类型转换为窄类型的过程。
function test(padding: number | string,input: string) {
if (typeof padding === 'number') {
return new Array(padding + 1).join(" ") + input;
}
return padding + input;
}
in操作符
type Bird = {
fly: () => void;
}
type Bear = {
run: () => void;
}
function move(Animal: Bird | Bear) {
if ('fly' in Animal) {
return Animal.fly();
}
return Animal.run();
}
类型谓词
类型谓词是用于告诉某个情况下某个变量的类型。
type Fish = {
name: string;
swim: () => void;
}
type Bird = {
name: string;
fly: () => void;
}
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim != undefined
}
function getSmallPet(): Fish | Bird {
let fish: Fish = {
name: 'sharkey',
swim: () => {}
};
let bird: Bird = {
name: 'sparrow',
fly: () => {}
}
return true ? bird : fish;
}
let pet = getSmallPet();
if (isFish(pet)) {
pet.swim();
} else {
pet.fly()
}
never类型和穷尽性检查
type Bird = {
kind: 'bird'
name: string;
}
type Animal = {
kind: 'animal'
name: string
}
function test(bird: Bird | Animal) {
switch (bird.kind) {
case 'bird':
return 1;
case 'animal':
return 666;
default:
const unknown: never = bird;
}
}
函数类型
function greeter(fn: (s: string) => void) {
fn('hello ts');
}
greeter((s: string) => {
console.log(s);
})
调用签名
调用签名主要是给函数绑定属性。
// 调用签名主要是给函数绑定属性
type DescribableFunction = {
description : string
(somArg: number): boolean
}
function doSomething(fn: DescribableFunction) {
console.log(fn.description + ' returned ' + fn(6)); // hello returned true
}
function fn1(n: number) {
console.log(n); // 6
return true;
}
fn1.description = 'hello'
doSomething(fn1);
构造签名
在调用签名的前面添加一个new就成为了一个构造签名了。
// 构造签名
class Ctor {
s: string
constructor(s: string) {
this.s = s;
}
}
type SomeConstructor = {
new (s: string): Ctor
}
function fn(ctor: SomeConstructor) {
return new ctor('hello')
}
const f = fn(Ctor)
console.log(f.s); // hello
泛型函数
泛型是不预先指定类型,而是在调用的时候才指定类型。
// 泛型
function firstElement(arr: Type[]): Type | undefined {
return arr[0];
}
const s = firstElement(['a','v','b']); // s是string类型
const n = firstElement([1,2,3]); // n是number类型
下面是一个多参数的泛型实例。
function map(arr: Input[],func: (arg: Input) => Output): Output[] {
return arr.map(func);
}
const parsed = map(['1','2','3'],(n) => parseInt(n)); // [1,2,3]
泛型函数的限制条件
泛型函数的限制条件是通过extends关键词实现的。
// 泛型函数的限制条件是通过extends关键词实现的,这里的extends并不是真的继承,而是一种限制。
function longest(a: Type,b: Type) {
if (a.length > b.length) {
return a;
} else {
return b;
}
}
const longerArray = longest([1,2],[2,3,4]);
const longerString = longest('felix','lu');
const notOk = longest(100,200) // 这里会报错
泛型函数指定类型参数
指定传给泛型的参数的类型。
function combine(arr1: Type[],arr2: Type[]): Type[] {
return arr1.concat(arr2);
}
const arr = combine(['a','b'],[1,2,3]);
console.log(arr); // ['a','b',1,2,3]
函数的可选参数
可选参数主要是通过冒号实现,表示该参数可以传递也可以不传递。
function f(n?: number) {
if (n) {
console.log('n is ',n);
} else {
console.log('n is undefined');
}
}
f()
f(11)
回调中的可选参数
表示回调函数中的某个参数是可选的。
function myForEach(arr: any[],callback: (arg: any, index?: number) => void) {
for (let i = 0; i < arr.length; i++) {
callback(arr[i],i);
}
}
myForEach([1,2,3],(a) => console.log(a));
myForEach([1,2,3],(a,i) => console.log(a,i));
函数重载
// 函数重载
function makeDate(timestamp: number): Date;
function makeDate(m: number,d: number,y: number): Date;
// 函数重载的实现
function makeDate(mOrTimestamp: number, d?: number,y?: number): Date {
if (d != undefined && y != undefined) {
return new Date(y,mOrTimestamp,d)
} else {
return new Date(mOrTimestamp);
}
}
const d1 = makeDate(123456);
const d2 = makeDate(5,6,7);
const d3 = makeDate(5,9) // 此时会报错,因为传参要满足重载的任意一个,而不是重载的实现
参数展开运算符
function multiply(n: number,...m: number[]) {
return m.map(x => n * x);
}
const a = multiply(10,1,2,3,4);
参数的解构赋值
function sum({a,b,c}: {a: number,b: number,c: number}) {
console.log(a + b + c);
}
sum({a: 10,b: 20,c: 30});
只读属性
只读属性只能读不能修改,这是对常量而言的,如果是引用类型的话,只要地址不变,其内部的变量是可以进行修改的。
interface SomeType {
readonly prop: string;
}
function doSomething(obj: SomeType) {
console.log(obj.prop);
obj.prop = '666' // 这一行会报错。
}
交叉类型
被交叉类型定义的对象,需要同时满足交叉类型中的所有定义。
interface Colorful {
color: string
}
interface Circle {
radius: number
}
type ColorfulCircle = Colorful & Circle;
const cc: ColorfulCircle = {
color: 'red',
radius: 100,
}
在泛型约束中使用类型参数
function getProperty(obj: Type,key: Key) {
return obj[key];
}
let x = {
a: 1,
b: 2,
c: 3,
d: 4
}
getProperty(x,'a');
getProperty(x,'m'); // 报错