TypeScript 概述
TypeScript 是一种将静态类型引入 JavaScript 的语言。 静态类型有两个主要优点:
- 类型安全
- 文档化
类型安全
编译器会进行类型检查,如果程序有错误,就会出现编译错误。
const message: number = 'hello hedy';
console.log(message);
没有编译的时候,webstorm或者VS code就会指出你是否使用不适当的类型编写代码,例如:
这样我们就可以及早发现错误。
文档化
看看下面的代码,你能说出什么类型作为参数以及返回什么类型的返回值吗?
function arrayMagic(numbers){
return numbers.map((element,index) => (index + 1) * element)
.filter(element => element % 2 ===0)
.reduce((acc,currentValue) => acc + currentValue)
}
但如果用TS写呢?
function arrayMagic(array: number[]): number {
return array
.map((element, index) => (index + 1) * element)
.filter((element) => element % 2 === 0)
.reduce((acc, currentValue) => acc + currentValue);
}
可以看到,当你传递一个充满数字类型的数组时,该方法就起作用了,并且它返回一个数字类型值作为返回值!
const numbers = [1, 2, 3, 4, 5];
const result = arrayMagic(numbers);
console.log(result); //20
// 1. 通过 `map` 方法,将输入数组中的每个元素与其索引加1相乘。
// 2. 通过 `filter` 方法,筛选出偶数元素。
// 3. 通过 `reduce` 方法,将筛选后的元素相加。
//
// 让我们计算一下给定的输入数组 `numbers = [1, 2, 3, 4, 5]` 经过 `arrayMagic` 函数后的结果:
//
// 1. `map` 阶段会将数组转换为 `[1 * 1, 2 * 2, 3 * 3, 4 * 4, 5 * 5]`,即 `[1, 4, 9, 16, 25]`。
// 2. `filter` 阶段会筛选出偶数元素,即 `[4, 16]`。
// 3. `reduce` 阶段会将筛选后的元素相加,得到 `4 + 16 = 20`。
//
// 所以,最后 `result` 的值是 `20`。
关于 TypeScript 类型
原始类型
- 布尔值(Boolean)
let isDone: boolean = false;
isDone
为boolean类型,false
设置为初始值。
- 数字(Number)
let decimal: number = 6;
decimal
类型为number,6设置为初始值。
- 字符串(String)
let color: string = "blue";
color = 'red';
color
为字符串类型,"blue"设置为初始值。后来改成'red'.
- Symbol
let sym1 = Symbol();
let sym2 = Symbol("key"); // 可选字符串键
"sym1" 和 "sym2" 都是 Symbol 类型,它们各自生成了新的 Symbol。"sym2" 在创建 Symbol 时指定了可选的字符串键 "key"。
Symbol 用于创建唯一的标识符。当你调用 Symbol()
函数时,它会创建一个新的 Symbol 值,这个值是独一无二的,与任何其他 Symbol 值都不同。换句话说,Symbol()
总是生成一个新的、唯一的值。
因此,以下的结果将会是 false。
let symbol1 = Symbol();
let symbol2 = Symbol();
console.log(symbol1 === symbol2); // false
Symbol 主要用于作为对象的属性键。当将 Symbol 用作键时,该属性将不会与任何其他字符串键发生冲突,这是因为 Symbol 是唯一的值。
let symbol1 = Symbol("key1");
let symbol2 = Symbol("key2");
let obj = {
[symbol1]: "value1",
[symbol2]: "value2"
};
console.log(obj[symbol1]); // "value1"
console.log(obj[symbol2]); // "value2"
- Null (空)
let n: null = null;
"n" 是 null 类型,其值被设置为 null。
- Undefined (未定义类型)
let u: undefined = undefined;
"u" 是 undefined 类型,其值被设置为 undefined。
特殊类型(special types)
- Any
let notSure: any = 4;
notSure = "maybe a string";
notSure = false;
"notSure" 是一个 any 类型,它一开始具有一个 number
类型的值为 4,然后被更改为一个 string
类型的值为 "maybe a string",最后又被更改为一个 boolean
类型的值为 false。any 类型通常用于绕过类型检查,但基本上应该避免使用它,因为它会降低 TypeScript 的类型检查能力,可能导致运行时错误。因此,最好在可能的情况下明确定义变量的类型,以充分利用 TypeScript 的类型检查功能。
- Void
function warnUser(): void {
console.log("This is a warning message");
}
warnUser 是一个 void
类型的函数,不返回有效的返回值。
- Never
function error(message: string): never {
throw new Error(message);
}
error函数是 never
类型,该函数始终会引发错误。因此,该函数不会返回任何返回值。
注意:void
和 never
的主要区别在于,void
表示函数不返回值,而 never
表示函数要么永不结束,要么一定引发错误。"
数组和元组
- Array(数组)
let list: number[] = [1, 2, 3];
list是一个number
类型的数组,[1, 2, 3]
设置为初始值。
- Tuple(元组)
let x: [string, number];
x = ["hello", 10];
"x" 是一个元组(tuple),其中定义了第一个元素为字符串类型,第二个元素为数字类型。它的初始值被设置为 ["hello", 10]
。
"元组" 是 TypeScript 中的一种数据结构,它允许您定义一个固定长度和特定类型的数组。在这种情况下,元组 "x" 包含两个元素,第一个是字符串 "hello",第二个是数字 10。
枚举和文字类型
- Enum(枚举)
enum Color {Red, Green, Blue}
let c: Color = Color.Green;
"Color" 是一个枚举(enum),它定义了三个值,分别是 Red、Green 和 Blue。"c" 是一个 Color 类型的变量,它的初始值被设置为 Color.Green
。
枚举允许您定义一组具名的常量值,这些值在代码中可以用来表示特定的状态或选项。在这种情况下,Color 枚举包含了三种颜色选项:红色、绿色和蓝色,而变量 "c" 的初始值是绿色。
- Literal Types(文字类型)
type Easing = "ease-in" | "ease-out" | "ease-in-out";
let easing: Easing = "ease-in";
"Easing" 是一个字面量类型(literal type),它定义了三个值:"ease-in"、"ease-out" 和 "ease-in-out"。"easing" 是一个 Easing 类型的变量,它的初始值被设置为 "ease-in"。
字面量类型允许您定义一个变量只能具有特定的字面值,这有助于确保代码的类型安全性。在这种情况下,"Easing" 类型允许的值只能是 "ease-in"、"ease-out" 或 "ease-in-out" 中的一个,而变量 "easing" 的初始值是 "ease-in"。
类型推断和类型断言
- 类型推断
let someValue = "this is a string";
let strLength = someValue.length;
someValue的类型没有明确指定,但是它被分配了一个字符串"this is a string",TypeScript 推断它是字符串类型。因此可以使用.length
属性。
- 类型断言
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
"someValue" 是一个 any 类型的变量,它的值被设置为字符串类型的值 "this is a string"。但是,在接下来的代码行中,使用了类型断言,形式为 (<string>someValue).length
。这意味着它将 "someValue" 视为字符串类型,并获取其 .length
属性。
类型断言用于告诉编译器,在某个特定的上下文中,您要将变量视为特定的类型,以便执行相关的操作。在这种情况下,通过类型断言,"someValue" 被视为字符串类型,以便获取其长度属性 .length
。
高级类型
- Union type(联合型)
let value: number | string;
value = 123; // OK
value = '123'; // OK
value可以采用数字或字符串类型。因此,可以设置类似的值123和'123'
- Intersection type(交叉口类型)
type First = { x: number };
type Second = { y: number };
let value: First & Second = { x: 1, y: 2 };
"value" 必须具有同时满足 "First" 类型和 "Second" 类型的特性。因此,需要设置一个对象,如 { x: 1, y: 2 }
,该对象包含了这两个属性。
- Type aliases(类型别名)
type StringOrNumber = string | number;
let sample: StringOrNumber;
sample = 123; // OK
sample = '123'; // OK
"StringOrNumber" 是一个类型别名,它表示可以是字符串类型或数字类型之一。因此,可以将类似于 123 或 '123' 的值分配给 "sample"。
- Generics(泛型)
function identity<T>(arg: T): T {
return arg;
}
let output = identity<string>("myString");
在这里,"identity" 函数是一个泛型函数,它以类型 T 作为参数,并返回相同的类型 T。在调用这个函数时,您需要指定具体的类型(在这里是字符串类型)。
React 中使用的 TypeScript 类型
在React的函数组件中,会接受 props 作为参数。要为这些 props 指定类型,可以使用TypeScript的接口(interface)或类型别名(type alias)。
- 使用
React.FC<接收类型>
的写法
//如果没有接收到Props
import React from 'react';
const Greeting = () => {
return <div>你好!</div>;
};
//使用单个Props
type GreetingProps = {
firstName: string;
};
const Greeting: React.FC<GreetingProps> = ({ firstName }) => {
return <p>你好,{firstName}</p>;
};
//多个Props
type UserProps = {
name: string;
age: number;
isLoggedIn: boolean;
};
const userState: React.FC<UserProps> = ({ name, age, isLoggedIn }) => {
return (
<div>
<p>名字:{name}</p>
<p>年龄:{age}</p>
<p>登录状态:{isLoggedIn ? '已登录' : '未登录'}</p>
</div>
);
};
接下来我们来看另一种写法,如下面的例子:
//如果没有接收到Props
import React from 'react';
const Greeting = () => {
return <div>你好!</div>;
};
//使用单个Props
type GreetingProps = {
firstName: string;
};
const Greeting = ({ firstName }: GreetingProps) => {
return <p>你好,{firstName}</p>;
};
//多个Props
type UserProps = {
name: string;
age: number;
isLoggedIn: boolean;
};
const userState = ({ name, age, isLoggedIn }: UserProps) => {
return (
<div>
<p>名字:{name}</p>
<p>年龄:{age}</p>
<p>登录状态:{isLoggedIn ? '已登录' : '未登录'}</p>
</div>
);
};
主要是看大家习惯哪一种写法啦!
children的特殊 prop
在React组件中,通常会接收名为 "children" 的特殊 prop。这个 prop 用于表示组件包装的JSX元素。在TypeScript中,可以使用 "ReactNode" 类型来为这个 prop 进行类型标注。
请注意,如果 "children" 只能接受特定类型的值,您可以直接将其限制为特定的类型(例如字符串),而不使用 "ReactNode"。
type CardProps = {
title: string,
children: React.ReactNode
}
const Card: React.FC<CardProps> = ({ title, children }) => {
return (
<div className="card">
<h2>{title}</h2>
<div className="card-content">{children}</div>
</div>
);
};
如果不使用FC类型,它将如下所示:
type CardProps = {
title: string,
children: React.ReactNode
}
const Card = ({ title, children }: CardProps) => {
return (
<div className="card">
<h2>{title}</h2>
<div className="card-content">{children}</div>
</div>
);
}
组件的返回值类型
在组件的返回值类型中,通常使用 "JSX.Element
" 或 "ReactElement
"。
JSX.Element
JSX.Element
是一种常用作 React 组件返回值的类型。它指示使用 JSX 语法定义 React 组件时返回的元素类型。
function HelloWorld(): JSX.Element {
return <h1>Hello, world!</h1>;
}
- ReactElement
"ReactElement
" 与 "JSX.Element
" 非常相似,但它可以包含更具体的信息。"ReactElement
" 用于表示React应该呈现的组件树的一部分。"ReactElement
" 具有两个主要属性,即 "type
" 和 "props
"。
function HelloWorld(): React.ReactElement {
return <h1>Hello, world!</h1>;
}
在实际的React开发中,通常不需要直接操作或处理 "React.ReactElement
" 的类型信息,因为React内部会自动处理和管理这些信息。"React.ReactElement
" 的类型信息主要用于理论和内部实现的目的,而在日常编码中,通常使用 "JSX.Element
" 就足够了。无论是使用 "React.ReactElement
" 还是 "JSX.Element
",在大多数情况下,开发人员不需要深入关注类型信息,React会在背后进行处理,使开发更加便捷。
评论(0)