likes
comments
collection
share

ts入门——深入理解 TypeScript 的类型TS 添加了可选的静态类型检查,使得开发者可以在开发阶段就发现类型错误

作者站长头像
站长
· 阅读数 22

TypeScript (TS)

TypeScript 是 JavaScript 的超集,这意味着 JS 中能实现的各种操作和语法,在 TS 中都可以实现。TS 添加了可选的静态类型检查,使得开发者可以在开发阶段就发现类型错误,从而提高代码质量和可维护性。此外,TypeScript 还包含了对类、接口、命名空间等面向对象编程特性的支持。

TS安装

npm i -g typescript  // 全局安装 TypeScript

如果想要运行 ts 则可以安装 ts-node。

npm i -g ts-node  // 全局安装 ts-node

ts-node 是一个实用工具,允许你在 Node.js 中直接运行 TypeScript 文件。例如ts-node add.ts,将执行 app.ts 文件中的代码,而无需显式地使用 tsc 命令将其编译为 JavaScript。

类型推断

在 ts 中,类型推断(Type Inference)就是当你没有显式地指定一个变量或参数的类型时,TypeScript 编译器会根据上下文信息来推断这些类型的可能值。ts 检查在编译阶段,所以在编写代码时就可以发现错误。

如下所示,let b = 'hello ts'在 ts 中会类型推断为let b: string

ts入门——深入理解 TypeScript 的类型TS 添加了可选的静态类型检查,使得开发者可以在开发阶段就发现类型错误

当已经显式指定 a 为 number 类型时,不能再为 a 赋值为其他类型。

ts入门——深入理解 TypeScript 的类型TS 添加了可选的静态类型检查,使得开发者可以在开发阶段就发现类型错误

ts 类型

any 类型

  1. 代表任何类型,any 可以赋值成任意类型的值,可以赋给其他类型。一般情况下不用 any,因为它会造成变量污染,例如 x 被声明为 any 类型后,它失去了具体的类型信息,编译器无法在编译阶段对它的使用进行有效的类型检查。
let x: any;
x = 1;
x = "hello";
let y: boolean = true;
y = x;
  1. 在 ts 文件中可以创建一个 tsconfig.json 文件进行配置,其中noImplicitAny 是一个重要的编译选项,默认值为 false ,它控制着 TypeScript 编译器是否允许隐式的 any 类型。当你设置 "noImplicitAny": false 时,意味着你允许 TypeScript 编译器接受隐式的 any 类型。
"compilerOptions": {
    "noImplicitAny": true // 不允许any
}

如果 noImplicitAny 设置为 true,那么这段代码在编译时会产生一个警告或错误,指出 xy 的类型没有显式指定。编译器会提示你需要为这些变量提供类型注解。

unknown类型

  1. 与 any 相似,unknown 可以赋值成任意类型的值,但是不可以赋给其他类型
ts入门——深入理解 TypeScript 的类型TS 添加了可选的静态类型检查,使得开发者可以在开发阶段就发现类型错误
  1. 不能访问类型为 unknown 变量上面的属性
let obj:unknown = {
    a: 1
}
console.log(obj.a); // obj 的类型是未知,不能访问 a 属性
ts入门——深入理解 TypeScript 的类型TS 添加了可选的静态类型检查,使得开发者可以在开发阶段就发现类型错误
  1. 收缩类型

“收缩类型”(narrowing)是指在运行时通过条件语句(如 if 语句)来缩小一个值的类型范围。当你使用 unknown 类型时,经常需要通过类型保护来进行类型收缩,以便安全地使用这些值。

let x: unknown = 1
x + 1  // 报错

// 使用 typeof 进行类型保护
if (typeof x === 'number') {
    // 在这个 if 块内,TypeScript 知道 x 是 number 类型
    x + 1;  // 不再报错
}

never 类型

never 类型表示的是那些永远不会出现的类型,常用来定义永不返回的函数。

function foo(): never {
    throw new Error('error')
}

// 这个函数永远不会返回
function loopForever(): never {
    while (true) {
        // 无限循环
    }
}

js中就有的类型

const a: boolean = true // 布尔类型
const b: string = "hello"
const c: number = 123
const d: symbol = Symbol()
const e: bigint = 123n

const obj: object = {}
const arr: Array<number> = [1, 2, 3]
const foo: Function = () => { }

// 允许any的情况下undefined和null 会被当成any
const un = undefined
const nul: null = null


// 大写的 String 专门用来声明包装类
const str = new String('hello')
const obj2 = new Object()

let o: Object
o = 1
o = '1'
o = undefined // 报错 undefined 没有构造函数

值类型

用一个值作为类型,例如:let x: 1;

// 值类型
let x: 'a' // 'a'类型

联合类型

表示多个类型的值之一。例如:let value: string | number;

// 联合类型
let y: string | number
y = 123
y = '123'

// 联合的值类型
function color(color: '红' | '黄') {

}
color('红')
color('黄')

交叉类型

表示多个类型的组合。例如:type DraggableAndResizable = Draggable & Resizable;

// 交叉类型
let obj3: {foo: string} & {bar: string}
obj3 = {
    foo: 'hello',
    bar: 'world'
}

type

类型别名,可以定义新的类型名称。例如:type Point = { x: number; y: number };

// type声明唯一
type Age = number // Age类型
let age: Age = 18

type World = 'world'
type Greeting = `hello ${World}`

type Common = string | number | boolean

数组

  1. 使用类型后缀 []

可以使用类型后缀 [] 来定义一个数组类型,其中包含特定类型的元素。

let arr: number[] = [1,2,3]
arr.push('4') // 报错 ts中数组里面要是同一个类型

let strings: string[] = ['a', 'b', 'c'];
let arr:(string | number)[] = [1,2,3,'hello']
  1. 使用 Array<T>

可以使用 Array 来定义数组类型,其中 T 是数组元素的类型。

let numbers: Array<number> = [1, 2, 3];
let strings: Array<string> = ['a', 'b', 'c'];
let arr: Array<string | number> = [1,2,3,'hello']
  1. 可以设置数组只读不写
const arr1: readonly number[] = [1,2,3] // 只读不可写
let arr2: ReadonlyArray<number> = [1]
let arr3: Readonly<number[]> = [1]

元组(Tuple)

元组类型允许你定义一个数组,其中元素的数量和类型都是固定的。元组允许数组存储不同类型,元组是ts特殊的数组类型。

// 元组声明写在方括号里面
let point: [number, number] = [10, 20];
let person: [string, number, boolean] = ['Alice', 25, true];
    
// 元组可以设置可选,用 ? 表示
let arr: [number , string?, boolean?] = [1]

函数

  1. 函数默认是 void 类型,函数 return 的是什么类型就是什么类型。
function foo() { // function foo1(): number
    let a = 1
    return a 
}

上面这段代码返回的是 a ,根据类型推断 a 是 number 类型,所以函数 foo 是 number 类型。

函数重载

函数重载(Overload)是 TypeScript 中的一种特性,允许你为同一个函数名称提供多个不同的函数签名(Signatures),以便根据参数的不同类型执行不同的逻辑。

// 函数重载 -- 当需要根据参数类型的不同执行不同的逻辑
function reverse(str: string): string
function reverse(arr: number[]): number[]
    
function reverse(str: string | number[]): string | number[] {
    if (typeof str === 'string') {
        return str.toString().split('').reverse().join('')
    }else {
        return str.slice().reverse()
    }
}
console.log(reverse('asadftrgy'));
console.log(reverse([1,2,3,4]));

这段代码定义了一个名为 reverse 的函数,该函数可以根据传入参数的类型执行不同的逻辑。具体来说,它有两个重载声明和一个实际的函数实现。

1. 函数重载声明
function reverse(str: string): string;
function reverse(arr: number[]): number[];

这两个声明定义了 reverse 函数的两种不同的用法:

  • 第一个声明表示 reverse 接受一个 string 类型的参数,并返回一个 string 类型的结果。
  • 第二个声明表示 reverse 接受一个 number[] 类型的参数,并返回一个 number[] 类型的结果。
2. 实现
function reverse(str: string | number[]): string | number[] {
    if (typeof str === 'string') {
        return str.toString().split('').reverse().join('');
    } else {
        return str.slice().reverse();
    }
}

这个函数的实际实现是一个多态函数,它接受一个联合类型 string | number[] 的参数,并根据参数的类型返回相应的结果:

  • 如果参数是 string 类型,那么函数会将其分割成字符数组,反转数组,然后重新连接成字符串。
  • 如果参数是 number[] 类型,那么函数会创建数组的一个浅拷贝,然后反转数组。
3. 调用
console.log(reverse('asadftrgy'));  // 输出反转后的字符串
console.log(reverse([1, 2, 3, 4]));  // 输出反转后的数组

这两个调用分别传递了字符串和数组给 reverse 函数,并打印反转后的结果。

对象

定义对象类型可以用 {}、object、Object,如下所示。

const obj1: {a: number, b: number} = {a: 1, b: 3}
const obj2: object = {a: 1}
const obj3: Object = {a: 1} 

总结

本文详细介绍了 TypeScript 中的类型,从基本类型到复杂的对象类型,涵盖了 TypeScript 中的主要类型概念和用法。希望可以给你带来帮助。

ts入门——深入理解 TypeScript 的类型TS 添加了可选的静态类型检查,使得开发者可以在开发阶段就发现类型错误

转载自:https://juejin.cn/post/7411345808526409782
评论
请登录