哈搂~大家好我是阿华,今天来跟大家分享 TypeScript 基础类型,
TypeScript 提供了多种类型,用于宣告变数、函数参数、函数传回值等,以协助开发者更準确地定义和使用资料。
以下是 TypeScript 中常见的一些类型介绍 :
基本原始(The primitives)型态:
常用的:number、string、boolean、null、undefined较少用的:symbol、bigint可以透过以下方法宣告变数的类型:
const strExample: string = "str ...";const numExample: number = 100;const boolExample: boolean = true; // or falseconst nullExample: null = null;const undefinedExample: undefined = undefined;const symbolExample: symbol = Symbol("name");const bigintExample: bigint = 10n;
宣告阵列(Array)类型
若是要宣告阵列类型如字串阵列、数字阵列、物件阵列,可以透过以下方法宣告变数的类型:
const strArray: string[] = ["str ...", "str 1 ..."];const numArray: number[] = [100, 101, 102];const boolArray: boolean[] = [true, false, false];const mixedArray: (string | null)[] = ["str", null, "str1"]; // '|' 表示 '或'
如果想要宣告一个固定长度和类型的阵列(tuple),可以透过以下方法宣告变数的类型:
const person: [string, number] = ["John", 30];
宣告物件(Object)类型
若是要宣告物件类型(Object),可以透过以下 Record 型别搭配指定泛类型的方法宣告类型:
const obj: Record<string, number> = { keyName: 100 };
上面例子中 Record 第一个可以传入的泛类型我们指定为 string,代表我们物件的 key 的类型是 string,
第二个可以传入的泛类型我们指定为 number,代表我们物件的 value 是 number,
Interface
又如果我们想指定物件内的多个属性的个别类型,
我们可以方便地透过 interface 关键字去宣告:
interface MyObj { props1: string; props2: number; props3: (string | null)[];}const obj: MyObj = { props1: "string...", props2: 101, props3: [null],};
宣告函数(Function)类型
若是要宣告函数(Function)类型,可以透过以下方法宣告类型:
// 一般函数function add(x: number, y: number): number { return x + y;}// 或以箭头函数宣告类型const add: (x: number, y: number) => number = (x, y) => x + y;
// 位置格式搭配中文解说// 一般函数function add(x: x的类型, y: y的类型): 函数返回的类型 { return x + y;}// 箭头函数 add 的类型const add: 整个箭头函数的类型 = (x, y) => x + y;// 整个箭头函数的类型 : (x: number, y: number) => number
上面两个例子中,都表示 add 这个函数,接受 x 跟 y 两个参数类型都是 number,并回传 number 类型
如果在使用 add 函数时,传入两个参数类型不是 number 时,就会提示错误
宣告枚举(Enum)类型
若是要宣告枚举(Enum)类型,可以透过以下方法宣告 :
enum:表示一组命名的常数值。
enum Color { Red, Green, Blue,}let favoriteColor: Color = Color.Blue;
上面例子在编译成 js 后,相当于有一个 Color 物件,所以可以以 Color.Blue 的方式使用
// enum Color {// Red,// Green,// Blue,// }// 编译后的结果 (v5.2.2, target:ES2017)var Color;(function (Color) { Color[(Color["Red"] = 0)] = "Red"; Color[(Color["Green"] = 1)] = "Green"; Color[(Color["Blue"] = 2)] = "Blue";})(Color || (Color = {}));// console.log(Color)// {// 0: "Red",// 1: "Green",// 2: "Blue",// Blue: 2,// Green: 1,// Red: 0,// };
宣告 any 类型
在某些情况我们不希望特定值导致类型检查错误时,我们可以使用 any 类型:
const value: any = 42; // 不管放什么类型的值都不会触发错误
直得注意的是,我们需要慎用 any,因为它会丧失类型检查的好处。
若不想丧失类型检查的好处,可以使用 unknown 来代替,
宣告 unknown 类型
unknown 顾名思义指的是未知的类型,就是你不知道它确切类型。
这通常用于处理来自不可信来源或动态资料的情况,或者当你需要编写通用的、类型安全的程式码,
而不知道值的类型是什么的时候使用。
例如:
let value: unknown = "Hello, TypeScript";let strLength: number = value.length;// 因为现在 value 的类型是 unknown,这里会显示错误 Object is of type 'unknown'.// 我们应该先断言他的类型为 stringlet strLength: number = (value as string).length;// Object is of type 'unknown'.
总之使用 unknown 有助于提高程式码的类型安全性,因为它要求你在使用值之前进行类型检查或类型断言,而不是如 any 一样丧失类型检查。
我们接着往下介绍几种常用的符号,
联合(Union)类型
如果我们想让变数可以有多种不同类型的值,我们可以使用联合(Union)类型:
let name: string | null = "John";// string | null:表示变数可以有是string 或 null
交集(Intersection)类型
如果我们想让变数'同时'具有多种类型的特性,我们可以使用交集(Intersection)类型:
// Person & Age:表示变数可以同时具有两种类型的特性。interface Person { name: string;}interface Age { age: number;}let john: Person & Age = { name: "John", age: 30 };
类型别名(Type Alias)
如果我们需要建立自订类型别名,用于简化複杂类型的表示我们可以使用类型别名(Type Alias):
type Point = { x: number; y: number };let origin: Point = { x: 0, y: 0 };
看到这里眼尖的大家可能会好奇 type 跟 interface 有什么不一样?
节录自官方说明:
Type aliases and interfaces are very similar, and in many cases you can choose between them freely. Almost all features of an interface are available in type, the key distinction is that a type cannot be re-opened to add new properties vs an interface which is always extendable.
type 跟 interface 两者非常像,基本上大多时候可以自由选择使用,两者不一样的关键点在 interface 同名字会继承,type 不会继承,基本上大多时候可以自由选择使用,例如:
// Interfaceinterface Animal { name: string;}interface Bear extends Animal { honey: boolean;}const bear = getBear();bear.name;bear.honey;// Typetype Animal = { name: string;};type Bear = Animal & { honey: boolean;};const bear = getBear();bear.name;bear.honey;
而两者不一样的关键点,例如:
// Interfaceinterface Animal { title: string;}interface Animal { ts: string;}const animal: Animal = { title: "str", ts: "str",}; // Animal继承了title与ts两个属性// Typetype Animal = { title: string;};type Animal = { ts: string;};// 发出错误 Error: Duplicate identifier 'Animal'.
Type Assertions (as)
而有时 TypeScript 无法推断出理想的类型资讯,所以我们会需要使用 Type Assertions (as)去断言类型,
例如:
const canvas = document.getElementById("canvas");// 推断 canvas 类型为 HTMLElement | null
但我们知道其实他的类型是 HTMLCanvasElement 比较精确,所以我们可以用 as 去断言他的类型为 HTMLCanvasElement
const myCanvas = document.getElementById("canvas") as HTMLCanvasElement;
unknown
另外这边补充一种用法,如果 TypeScript 类型资讯差异太大会无法直接用 as 断言,会需要先断言成 unknown 在断言成想要的类型,例如:
interface Color { detail: string;}interface Table { color: string;}const table: Table = { detail: "string",} as Table;// 会显示错误,因为 Table 没有 detail 属性// Conversion of type '{ detail: string; }' to type 'Table' may be a mistake because neither type//sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.// Property 'color' is missing in type '{ detail: string; }' but required in type 'Table'.
先断言成 unknown 在断言成想要的类型可以通过检查,但这里举的是一个极端的例子,也要谨慎使用
const table: Table = { detail: "string",} as unknown as Table;
never
再来是 never 类型,它用于表达不正常或不可到达的程式码路径,以增强类型安全性。当你看到 never 类型时,通常意味着某些特殊情况或不正常情况的处理。之后我们在聊 Conditional Types 时,会再把 never 拿出来鞭鞭尸
上面这些是 TypeScript 中的一些常见类型。透过使用这些类型,可以增加程式码的可读性、可维护性和类型安全性,从而更轻鬆地开发複杂的应用程式。另外根据需求,你可以建立自订类型和接口,以满足特定场景的需求。
那这回我们就说到这里,下回我们聊聊 Narrowing~
参考资料:
https://www.typescriptlang.org/docs/handbook/2/basic-types.html