首页
Preview

从 TypeScript 类型概述到 React 中的处理类型

TypeScript 概述

TypeScript 是一种将静态类型引入 JavaScript 的语言。 静态类型有两个主要优点:

  • 类型安全
  • 文档化

类型安全

编译器会进行类型检查,如果程序有错误,就会出现编译错误。

const message: number = 'hello hedy';
console.log(message);

没有编译的时候,webstorm或者VS code就会指出你是否使用不适当的类型编写代码,例如:

image.png

这样我们就可以及早发现错误。

文档化

看看下面的代码,你能说出什么类型作为参数以及返回什么类型的返回值吗?

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 类型,该函数始终会引发错误。因此,该函数不会返回任何返回值。

注意:voidnever 的主要区别在于,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会在背后进行处理,使开发更加便捷。

版权声明:本文内容由TeHub注册用户自发贡献,版权归原作者所有,TeHub社区不拥有其著作权,亦不承担相应法律责任。 如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

点赞(0)
收藏(0)
大前端打手
假程序员

评论(0)

添加评论