你不知道的 TypeScript 高级类型(下)

简介: 你不知道的 TypeScript 高级类型

你不知道的 TypeScript 高级类型(上)https://developer.aliyun.com/article/1411324


5. 条件类型


(1)基本概念

条件类型根据条件来选择两种可能的类型之一,就像 JavaScript 中的三元运算符一样。其语法如下所示:


T extends U ? X : Y

上述类型就意味着当 T 可分配给(或继承自)U 时,类型为 X,否则类型为 Y

看一个简单的例子,一个值可以是用户的出生日期或年龄。如果是出生日期,那么这个值的类型就是 number;如果是年龄,那这个值的类型就是 string。下面定义了三个类型:


type Dob = string;
type Age = number;
type UserAgeInformation = T extends number ? number : string;

其中 TUserAgeInformation 的泛型参数,可以在这里传递任何类型。 如果 T 扩展了 number,那么类型就是 number,否则就是 string。 如果希望 UserAgeInformationnumber,就可以将 Age 传递给 T,如果希望是一个 string,就可以将 Dob 传递给 T


type Dob = string;
type Age = number;
type UserAgeInformation<T> = T extends number ? number : string;
let userAge:UserAgeInformation<Age> = 100;
let userDob:UserAgeInformation<Dob> = '25/04/1998';

(2)创建自定义条件类型

单独使用条件类型可能用处不是很大,但是结合泛型使用时就非常有用。一个常见的用例就是使用带有 never 类型的条件类型来修剪类型中的值。


type NullableString = string | null;
let itemName: NullableString;
itemName = null;
itemName = "Milk";
console.log

其中 NullableString 可以是 stringnull 类型,它用于 itemName 变量。定义一个名为 NoNull 的类型别名:


type NoNull

我们想从类型中剔除 null,需要通过条件来检查类型是否包含 null


type NoNull = T extends null;
当这个条件为 true 时,不想使用该类型,返回 never 类型:


type NoNull = T extends null ? never

当这个条件为 false 时,说明类型中不包含 null,可以直接返回 T


type NoNull = T extends null ? never : T;

itemName 变量的类型更改为 NoNull


let itemName: NoNull<NullableString>;

TypeScript 有一个类似的实用程序类型,称为 NonNullable,其实现如下:


type NonNullable = T extends null | undefined ? never : T;

NonNullableNoNull 之间的区别在于 NonNullable 将从类型中删除 undefined 以及 null

(3)条件类型的类型推断

条件类型提供了一个infer关键字用来推断类型。下面来定义一个条件类型,如果传入的类型是一个数组,则返回数组元素的类型;如果是一个普通类型,则直接返回这个类型。如果不使用  infer 可以这样写:


type Type = T extends any[] ? T[number] : T;
type test = Type<string[]>; // string
type test2 = Type<string>;  // string

如果传入 Type 的是一个数组类型,那么返回的类型为T[number],即该数组的元素类型,如果不是数组,则直接返回这个类型。这里通过索引访问类型T[number]来获取类型,如果使用 infer 关键字则无需手动获取:


type Type = T extends Array ? U : T;
type test = Type<string[]>; // string
type test2 = Type<string>;  // string

这里 infer 能够推断出 U 的类型,并且供后面使用,可以理解为这里定义了一个变量 U 来接收数组元素的类型。


6. 类型推断


(1)基础类型

在变量的定义中如果没有明确指定类型,编译器会自动推断出其类型:


let name = "zhangsan";
name = 123; // error 不能将类型“123”分配给类型“string”

在定义变量 name 时没有指定其类型,而是直接给它赋一个字符串。当再次给 name 赋一个数值时,就会报错。这里,TypeScript 根据赋给 name 的值的类型,推断出 name 是 string 类型,当给 string 类型的 name 变量赋其他类型值的时候就会报错。这是最基本的类型推论,根据右侧的值推断左侧变量的类型。

(2)多类型联合

当定义一个数组或元组这种包含多个元素的值时,多个元素可以有不同的类型,这时 TypeScript 会将多个类型合并起来,组成一个联合类型:


let arr = [1, "a"];
arr = ["b", 2, false]; // error 不能将类型“false”分配给类型“string | number”

可以看到,此时的 arr 中的元素被推断为string | number,也就是元素可以是 string 类型也可以是 number 类型,除此之外的类型是不可以的。

再来看一个例子:


let value = Math.random() * 10 > 5 ? 'abc' : 123
value = false // error 不能将类型“false”分配给类型“string | number”

这里给value赋值为一个三元表达式的结果,Math.random() * 10的值为0-10的随机数。如果这个随机值大于5,则赋给 value的值为字符串abc,否则为数值123。所以最后编译器推断出的类型为联合类型string | number,当给它再赋值false时就会报错。

(3)上下文类型

上面的例子都是根据=右侧值的类型,推断左侧值的类型。而上下文类型则相反,它是根据左侧的类型推断右侧的类型:


window.onmousedown = function(mouseEvent) {
  console.log(mouseEvent.a); // error 类型“MouseEvent”上不存在属性“a”
};

可以看到,表达式左侧是 window.onmousedown(鼠标按下时触发),因此 TypeScript 会推断赋值表达式右侧函数的参数是事件对象,因为左侧是 mousedown 事件,所以 TypeScript 推断 mouseEvent 的类型是 MouseEvent。在回调函数中使用 mouseEvent 时,可以访问鼠标事件对象的所有属性和方法,当访问不存在属性时,就会报错。


7. 类型保护


类型保护实际上是一种错误提示机制,类型保护是可执行运行时检查的一种表达式,用于确保该类型在一定的范围内。类型保护的主要思想是尝试检测属性、方法或原型,以确定如何处理值。

(1)instanceof 类型保护

instanceof是一个内置的类型保护,可用于检查一个值是否是给定构造函数或类的实例。通过这种类型保护,可以测试一个对象或值是否是从一个类派生的,这对于确定实例的类型很有用。

instanceof 类型保护的基本语法如下:


objectVariable instanceof ClassName ;

来看一个例子:


class CreateByClass1 {
  public age = 18;
  constructor() {}
}
class CreateByClass2 {
  public name = "TypeScript";
  constructor() {}
}
function getRandomItem() {
  return Math.random() < 0.5 
    ? new CreateByClass1() 
    : new CreateByClass2(); // 如果随机数小于0.5就返回CreateByClass1的实例,否则返回CreateByClass2的实例
}
const item = getRandomItem();
// 判断item是否是CreateByClass1的实例
if (item instanceof CreateByClass1) { 
  console.log(item.age);
} else {
  console.log(item.name);
}

这里 if 的判断逻辑中使用 instanceof 操作符判断 item 。如果是 CreateByClass1 创建的,那它就有 age 属性;如果不是,那它就有 name 属性。

(2)typeof 类型保护

typeof 类型保护用于确定变量的类型,它只能识别以下类型:

  • boolean
  • string
  • bigint
  • symbol
  • undefined
  • function
  • number

对于这个列表之外的任何内容,typeof 类型保护只会返回 objecttypeof 类型保护可以写成以下两种方式:


typeof v !== "typename"
typeof v === "typename"

typename 只能是numberstringbooleansymbol四种类型,在 TS 中,只会把这四种类型的 typeof 比较识别为类型保护。

在下面的例子中,StudentId 函数有一个 string | number 联合类型的参数 x。如果变量 x 是字符串,则会打印 Student;如果是数字,则会打印 Idtypeof 类型保护可以从 x 中提取类型:


function StudentId(x: string | number) {
    if (typeof x == 'string') {
        console.log('Student');
    }
    if (typeof x === 'number') {
        console.log('Id');
    }
}
StudentId(`446`); // Student
StudentId(446);   // Id

(3)in 类型保护

in 类型保护可以检查对象是否具有特定属性。它通常返回一个布尔值,指示该属性是否存在于对象中。

in 类型保护的基本语法如下:


propertyName in objectName

来看一个例子:


interface Person {
  firstName: string;
  surname: string;
}
interface Organisation {
  name: string;
}
type Contact = Person | Organisation;
function sayHello(contact: Contact) {
  if ("firstName" in contact) {
    console.log(contact.firstName);
  }
}

in 类型保护检查参数 contact 对象中是否存在 firstName属性。 如果存在,就进入if 判断,打印contact.firstName的值。

(4)自定义类型保护

来看一个例子:


const valueList = [123, "abc"];
const getRandomValue = () => {
  const number = Math.random() * 10; // 这里取一个[0, 10)范围内的随机值
  if (number < 5) {
    return valueList[0]; // 如果随机数小于5则返回valueList里的第一个值,也就是123
  }else {
    return valueList[1]; // 否则返回"abc"
  }
};
const item = getRandomValue();
if (item.length) {
  console.log(item.length); // error 类型“number”上不存在属性“length”
} else {
  console.log(item.toFixed()); // error 类型“string”上不存在属性“toFixed”
}

这里,getRandomValue 函数返回的元素是不固定的,有时返回 number 类型,有时返回 string 类型。使用这个函数生成一个值 item,然后通过是否有 length 属性来判断是 string 类型,如果没有 length 属性则为 number 类型。在 JavaScript 中,这段逻辑是没问题的。但是在 TypeScript 中,因为 TS 在编译阶段是无法识别 item 的类型的,所以当在 if 判断逻辑中访问 itemlength 属性时就会报错,因为如果 itemnumber 类型的话是没有 length 属性的。

这个问题可以通过类型断言来解决,修改判断逻辑即可:


if ((<string>item).length) {
  console.log((<string>item).length);
} else {
  console.log((<number>item).toFixed());
}

这里通过使用类型断言告诉 TS 编译器,if 中的 itemstring 类型,而 else 中的是 number 类型。这样做虽然可以,但是需要在使用 item 的地方都使用类型断言来说明,显然有些繁琐。

可以使用自定义类型保护来解决上述问题:


const valueList = [123, "abc"];

const getRandomValue = () => {
  const number = Math.random() * 10; // 这里取一个[0, 10)范围内的随机值
  if (number < 5) return valueList[0]; // 如果随机数小于5则返回valueList里的第一个值,也就是123
  else return valueList[1]; // 否则返回"abc"
};
function isString(value: number | string): value is string {
  const number = Math.random() * 10
  return number < 5;
}
const item = getRandomValue();
if (isString(item)) {
  console.log(item.length); // 此时item是string类型
} else {
  console.log(item.toFixed()); // 此时item是number类型
}

首先定义一个函数,函数的参数 value 就是要判断的值。这里 value 的类型可以为 numberstring,函数的返回值类型是一个结构为 value is type 的类型谓语,value 的命名无所谓,但是谓语中的 value 名必须和参数名一致。而函数里的逻辑则用来返回一个布尔值,如果返回为 true,则表示传入的值类型为is后面的 type

使用类型保护后,if 的判断逻辑和代码块都无需再对类型做指定工作,不仅如此,既然 itemstring类型,则 else 的逻辑中,item 一定是联合类型中的另外一个,也就是 number 类型。


8. 类型断言


(1)基本使用

TypeScrip的类型系统很强大,但有时它是不如我们更了解一个值的类型。这时,我们更希望 TypeScript 不要进行类型检查,而是让我们自己来判断,这时就用到了类型断言。

使用类型断言可以手动指定一个值的类型。类型断言像是一种类型转换,它把某个值强行指定为特定类型,下面来看一个例子:


const getLength = target => {
  if (target.length) {
    return target.length;
  } else {
    return target.toString().length;
  }
};

这个函数接收一个参数,并返回它的长度。这里传入的参数可以是字符串、数组或是数值等类型的值,如果有 length 属性,说明参数是数组或字符串类型,如果是数值类型是没有 length 属性的,所以需要把数值类型转为字符串然后再获取 length 值。现在限定传入的值只能是字符串或数值类型的值:


const getLength = (target: string | number): number => {
  if (target.length) { // error 类型"string | number"上不存在属性"length"
    return target.length; // error  类型"number"上不存在属性"length"
  } else {
    return target.toString().length;
  }
};

当 TypeScript 不确定一个联合类型的变量到底是哪个类型时,就只能访问此联合类型的所有类型里共有的属性或方法,所以现在加了对参数target和返回值的类型定义之后就会报错。

这时就可以使用类型断言,将target的类型断言成string类型。它有两种写法:valuevalue as type


// 这种形式是没有任何问题的,建议使用这种形式
const getStrLength = (target: string | number): number => {
  if ((target as string).length) {      
    return (target as string).length; 
  } else {
    return target.toString().length;
  }
};
// 这种形式在JSX代码中不可以使用,而且也是TSLint不建议的写法
const getStrLength = (target: string | number): number => {
  if ((<string>target).length) {      
    return (<string>target).length; 
  } else {
    return target.toString().length;
  }
};

类型断言不是类型转换,断言成一个联合类型中不存在的类型是不允许的。

注意: 不要滥用类型断言,在万不得已的情况下使用要谨慎,因为强制把某类型断言会造成 TypeScript 丧失代码提示的能力。

(2)双重断言

虽然类型断言是强制性的,但并不是万能的,在一些情况下会失效:


interface Person {
  name: string;
  age: number;
}
const person = 'ts' as Person; // Error

这时就会报错,很显然不能把 string 强制断言为一个接口 Person ,但是并非没有办法,此时可以使用双重断言:


interface Person {
  name: string;
  age: number;
}
const person = 'ts' as any as Person;

先把类型断言为 any ,再接着断言为想断言的类型就能实现双重断言,当然上面的例子肯定说不通的,双重断言我们也更不建议滥用,但是在一些少见的场景下也有用武之地。

(3)显式赋值断言

先来看两个关于nullundefined的知识点。

① 严格模式下 null 和 undefined 赋值给其它类型值

当在 tsconfig.json 中将 strictNullChecks 设为 true 后,就不能再将 undefinednull 赋值给除它们自身和void 之外的任意类型值了,但有时确实需要给一个其它类型的值设置初始值为空,然后再进行赋值,这时可以自己使用联合类型来实现 nullundefined 赋值给其它类型:


let str = "ts";
str = null; // error 不能将类型“null”分配给类型“string”
let strNull: string | null = "ts"; // 这里你可以简单理解为,string | null即表示既可以是string类型也可以是null类型
strNull = null; // right
strNull = undefined; // error 不能将类型“undefined”分配给类型“string | null”

注意,TS 会将 undefinednull 区别对待,这和 JavaScript 的本意也是一致的,所以在 TS 中,string|undefinedstring|nullstring|undefined|null是三种不同的类型。

② 可选参数和可选属性

如果开启了 strictNullChecks,可选参数会被自动加上 |undefined


const sum = (x: number, y?: number) => {
  return x + (y || 0);
};
sum(1, 2); // 3
sum(1); // 1
sum(1, undefined); // 1
sum(1, null); // error Argument of type 'null' is not assignable to parameter of type 'number | undefined'

根据错误信息看出,这里的参数 y 作为可选参数,它的类型就不仅是 number 类型了,它可以是 undefined,所以它的类型是联合类型 number | undefined

TypeScript 对可选属性和对可选参数的处理一样,可选属性的类型也会被自动加上 |undefined


interface PositionInterface {
  x: number;
  b?: number;
}
const position: PositionInterface = {
  x: 12
};
position.b = "abc"; // error
position.b = undefined; // right
position.b = null; // error

看完这两个知识点,再来看看显式赋值断言。当开启 strictNullChecks 时,有些情况下编译器是无法在声明一些变量前知道一个值是否是 null 的,所以需要使用类型断言手动指明该值不为 null。下面来看一个编译器无法推断出一个值是否是null的例子:


function getSplicedStr(num: number | null): string {
  function getRes(prefix: string) { // 这里在函数getSplicedStr里定义一个函数getRes,我们最后调用getSplicedStr返回的值实际是getRes运行后的返回值
    return prefix + num.toFixed().toString(); // 这里使用参数num,num的类型为number或null,在运行前编译器是无法知道在运行时num参数的实际类型的,所以这里会报错,因为num参数可能为null
  }
  num = num || 0.1; // 这里进行了赋值,如果num为null则会将0.1赋给num,所以实际调用getRes的时候,getRes里的num拿到的始终不为null
  return getRes("lison");
}

因为有嵌套函数,而编译器无法去除嵌套函数的 null(除非是立即调用的函数表达式),所以需要使用显式赋值断言,写法就是在不为 null 的值后面加个!。上面的例子可以这样改:


function getSplicedStr(num: number | null): string {
  function getLength(prefix: string) {
    return prefix + num!.toFixed().toString();
  }
  num = num || 0.1;
  return getLength("lison");
}

这样编译器就知道 num 不为 null,即便 getSplicedStr 函数在调用的时候传进来的参数是 null,在 getLength 函数中的 num 也不会是 null

(4)const 断言

const 断言是 TypeScript 3.4 中引入的一个实用功能。在 TypeScript 中使用 as const 时,可以将对象的属性或数组的元素设置为只读,向语言表明表达式中的类型不会被扩大(例如从 42 到 number)。


function sum(a: number, b: number) {
  return a + b;
}
// 相当于 const arr: readonly [3, 4]
const arr = [3, 4] as const;
console.log(sum(...arr)); // 7

这里创建了一个 sum 函数,它以 2 个数字作为参数并返回其总和。const 断言使我们能够告诉 TypeScript 数组的类型不会被扩展,例如从 [3, 4]number[]。通过 as const,使得数组成为只读元组,因此其内容是无法更改的,可以在调用 sum 函数时安全地使用这两个数字。

如果试图改变数组的内容,会得到一个错误:


function sum(a: number, b: number) {
  return a + b;
}
// 相当于 const arr: readonly [3, 4]
const arr = [3, 4] as const;
// 类型“readonly [3, 4]”上不存在属性“push”。
arr.push(5);

因为使用了 const 断言,因此数组现在是一个只读元组,其内容无法更改,并且尝试这样做会在开发过程中导致错误。

如果尝试在不使用 const 断言的情况下调用 sum 函数,就会得到一个错误:


function sum(a: number, b: number) {
  return a + b;
}
// 相当于 const arr: readonly [3, 4]
const arr = [3, 4];
// 扩张参数必须具有元组类型或传递给 rest 参数。
console.log(sum(...arr)); // 👉️ 7

TypeScript 警告我们,没有办法知道 arr 变量的内容在其声明和调用 sum() 函数之间没有变化。

如果不喜欢使用 TypeScript 中的枚举,也可以使用 const 断言作为枚举的替代品:


// 相当于 const Pages: {readonly home: '/'; readonly about: '/about'...}
export const Pages = {
  home: '/',
  about: '/about',
  contacts: '/contacts',
} as const;

如果尝试更改对象的任何属性或添加新属性,就会收到错误消息:


// 相当于 const Pages: {readonly home: '/'; readonly about: '/about'...}
export const Pages = {
  home: '/',
  about: '/about',
  contacts: '/contacts',
} as const;
// 无法分配到 "about" ,因为它是只读属性。
Pages.about = 'hello';
// 类型“{ readonly home: "/"; readonly about: "/about"; readonly contacts: "/contacts"; }”上不存在属性“test”。
Pages.test = 'hello';

需要注意,const 上下文不会将表达式转换为完全不可变的。来看例子:


const arr = ['/about', '/contacts'];
// 相当于 const Pages: {readonly home: '/', menu: string[]}
export const Pages = {
  home: '/',
  menu: arr,
} as const;
Pages.menu.push('/test'); // ✅

这里,menu 属性引用了一个外部数组,我们可以更改其内容。如果在对象上就地定义了数组,我们将无法更改其内容。


// 相当于 const Pages: {readonly home: '/', readonly menu: string[]}
export const Pages = {
  home: '/',
  menu: ['/about'],
} as const;
// 类型“readonly ["/about"]”上不存在属性“push”。
Pages.menu.push('/test');

(5)非空断言

在 TypeScript 中感叹号 ( ! ) 运算符可以使编译器忽略一些错误,下面就来看看它有哪些实际的用途的以及何时使用。

① 非空断言运算符

感叹号运算符称为非空断言运算符,添加此运算符会使编译器忽略undefinednull类型。来看例子:


const parseValue = (value: string) => {
    // ...
};
const prepareValue = (value?: string) => {
    // ...
    parseValue(value);
};

对于 prepareValue 方法的 value 参数,TypeScript就会报出以下错误:


类型“string | undefined”的参数不能赋给类型“string”的参数。
不能将类型“undefined”分配给类型“string”。

因为我们希望 prepareValue 函数中的 valueundefinedstring,但是我们将它传递给了 parseValue 函数,它的参数只能是 string。所以就报了这个错误。

但是,在某些情况下,我们可以确定 value 不会是 undefined,而这就是需要非空断言运算符的情况:


const parseValue = (value: string) => {
  // ...
};
const prepareValue = (value?: string) => {
  // ...
  parseValue(value!);
};

这样就不会报错了。但是,在使用它时应该非常小心,因为如果 value 的值是undefined ,它可能会导致意外的错误。

② 使用示例

既然知道了非空断言运算符,下面就来看几个真实的例子。

在列表中搜索是否存在某个项目:


interface Config {
  id: number;
  path: string;
}
const configs: Config[] = [
  {
    id: 1,
    path: "path/to/config/1",
  },
  {
    id: 2,
    path: "path/to/config/2",
  },
];
const getConfig = (id: number) => {
  return configs.find((config) => config.id === id);
};
const config = getConfig(1);

由于搜索的内容不一定存在于列表中,所以 config 变量的类型是 Config | undefined,我们就可以使用可以使用费控断言运算符告诉 TypeScript,config 应该是存在的,因此不必假设它是 undefined


const getConfig = (id: number) => {
  return configs.find((config) => config.id === id)!;
};
const config = getConfig(1);

这时,config 变量的类型就是 Config。这时再从 config 中获取任何属性时,就不需要再检查它是否存在了。

再来看一个例子,React 中的 Refs 提供了一种访问 DOM 节点或 React 元素的方法:


const App = () => {
  const ref = useRef<HTMLDivElement>(null);
  const handleClick = () => {
    if(ref.current) {
      console.log(ref.current.getBoundingClientRect());
    }
  };
  return (
    <div className="App" ref={ref}>
      <button onClick={handleClick}>Click</button>
    </div>
  );
};

这里创建了一个简单的组件,它可以访问 class 为 App 的 DOM 节点。组件中有一个按钮,当点击该按钮时,会显示元素的大小以及其在视口中的位置。我们可以确定被访问的元素是在点击按钮后挂载的,所以可以在 TypeScript 中添加非空断言运算符表示这个元素是一定存在的:


const App = () => {
  const handleClick = () => {
    console.log(ref.current!.getBoundingClientRect());
  };
};

当使用非空断言运算符时,就表示告诉TypeScript,我比你更了解这个代码逻辑,会为此负责,所以我们需要充分了解自己的代码之后再确定是否要使用这个运算符。否则,如果由于某种原因断言不正确,则会发生运行时错误。

相关文章
|
2月前
|
JavaScript 前端开发 安全
深入理解TypeScript:增强JavaScript的类型安全性
【10月更文挑战第8天】深入理解TypeScript:增强JavaScript的类型安全性
49 0
|
2月前
|
JavaScript 前端开发 开发者
深入理解TypeScript:类型系统与实用技巧
【10月更文挑战第8天】深入理解TypeScript:类型系统与实用技巧
|
15天前
|
JavaScript 安全 前端开发
TypeScript类型声明:基础与进阶
通过本文的介绍,我们详细探讨了TypeScript的基础与进阶类型声明。从基本数据类型到复杂的泛型和高级类型,TypeScript提供了丰富的工具来确保代码的类型安全和可维护性。掌握这些类型声明能够帮助开发者编写更加健壮和高效的代码,提高开发效率和代码质量。希望本文能为您在使用TypeScript时提供实用的参考和指导。
26 2
|
28天前
|
JavaScript 开发者
在 Babel 插件中使用 TypeScript 类型
【10月更文挑战第23天】可以在 Babel 插件中更有效地使用 TypeScript 类型,提高插件的开发效率和质量,减少潜在的类型错误。同时,也有助于提升代码的可理解性和可维护性,使插件的功能更易于扩展和升级。
|
2月前
|
JavaScript 前端开发
TypeScript【类型别名、泛型】超简洁教程!再也不用看臭又长的TypeScript文档了!
【10月更文挑战第11天】TypeScript【类型别名、泛型】超简洁教程!再也不用看臭又长的TypeScript文档了!
|
2月前
|
JavaScript 前端开发 安全
TypeScript【基础类型】超简洁教程!再也不用看臭又长的TypeScript文档了!
【10月更文挑战第9天】TypeScript【基础类型】超简洁教程!再也不用看臭又长的TypeScript文档了!
|
2月前
|
JavaScript 前端开发 开发者
深入理解TypeScript:类型系统与最佳实践
【10月更文挑战第8天】深入理解TypeScript:类型系统与最佳实践
|
2月前
|
移动开发 JavaScript 前端开发
TypeScript:数组类型&函数使用&内置对象
本文介绍了 TypeScript 中的数组类型、对象数组、二维数组、函数、函数重载、内置对象等概念,并通过代码示例详细展示了它们的使用方法。还提供了一个使用 HTML5 Canvas 实现的下雨效果的小案例。
|
27天前
|
JavaScript 前端开发 安全
TypeScript进阶:类型系统与高级类型的应用
【10月更文挑战第25天】TypeScript作为JavaScript的超集,其类型系统是其核心特性之一。本文通过代码示例介绍了TypeScript的基本数据类型、联合类型、交叉类型、泛型和条件类型等高级类型的应用。这些特性不仅提高了代码的可读性和可维护性,还帮助开发者构建更健壮的应用程序。
26 0
|
2月前
|
JavaScript 前端开发 开发者
深入理解TypeScript:类型系统与实用技巧
【10月更文挑战第8天】深入理解TypeScript:类型系统与实用技巧