1. 反应。 FC注释存在一些问题。是否先使用该类型作为注解存在一些争议,因为该类型破坏了 JSX Librarymanagedattributes,导致它忽略了函数和类组件的 defaultsProps 和 displayName 等参数,查看详情另外无法返回类组件等props的children详见(这个问题可以通过显式定义children属性或者修改源码来解决)。另外,FC 总是在@types/react18 之前隐式定义children。即使您的 Props 注解没有定义子项,您仍然可以在参数中对其进行解构。

  2. 反应。可以在@types/react Voidfunctioncomponent 的 16.8 和 18 版本之间使用,或者 react VFC 通过指定 props 必须显示的定义来替换它,以便在函数体中使用它

3.因为编译器仅限于函数组件,所以不能返回jsx和null以外的值。如果确实需要返回这两个以外的值,可以使用类型断言,比如

const MyArrayComponent u003d () u003d> (Array(5).fill(<div/>) as any) as JSX.Element

React.FC<Props> React.Component<Props,state>

  1. 开发通用类组件

// 使用时约束其道具类型

类型 SelectProps<T> u003d {项目:T[]};

类 Select<T> 扩展 React.Component<SelectProps<T>, {}> {

}

// 使用

const Form u003d () u003d> <Select<string> itemsu003d{['a','b']}>

1.开发通用功能

函数 foo<T>(x:T): T{

返回 x

}

// 箭头泛型函数需要用扩展提示编辑器。这是一个通用函数

const foo u003d <T extends Record<string,unknown>>() u003d> {}

7.React.ReactElement可以通过传入泛型类型来注解类或函数组件的实例化结果

类 MyAwesomeComponent 扩展 React.Component {

渲染() {

返回 <div>你好</div>;

}

}

const foo: React.ReactElement<MyAwesomeComponent> u003d <MyAwesomeComponent />; // 好的

常量栏:React.ReactElement<MyAwesomeComponent> u003d <NotMyAwesomeComponent />; // 错误

  1. 使用状态<>() 。奇异技能:

常量 [user,setUser] u003d React.useState<IUser |空>(空);

const [user,setUser] u003d React.useState<IUser>({} 作为 IUser)

1、reducer函数形参中intialState的类型注解可以直接从typeOf中获取其类型,

action 参数可以使用联合类型 live AnyAction 注解(来自'redux'),

通用注释

从 'redux' 导入 { Reducer };

导出函数reducer:

减速器<AppState, Action>() {}

10\。 Useref<>(),特殊技能:

// 如果可能,尝试使用特定类型

// 比如使用 HTMLDivElement 比 HTMLElement 好很多,比 Element 好很多

函数 Foo(){

常量 divRef u003d useRef<HTMLDivElement>(null);

返回<div>等<div/>

}

11.类型断言:as /泛型注解(不能在React中使用)/删除null或未定义的断言!

// 非空断言运算符

const fooRef u003d useRef<字符串>(null!)

const foo u003d name!.chartAt(0))

1.函数执行结果给其他变量赋值时,会发现变量的注解有问题

function fn(){return ['1',false] };

类型 AType u003d 字符串[]

let a:AType u003d fn() // 错误

// 1. 将其更改为将 ['1',false] 作为任何 [] 返回或将 ['1',false] 作为字符串 [] 返回。如果它是只读的,它可以是 const

// 2. type Atype u003d (string | boolean) [],但是已经不符合实际意思了

// 3.react 团队建议你自定义hook return 值超过两个的时候使用object

13.createContext

键入主题 u003d '光' | '黑暗的'

const TeemeContext u003d React.createContext<Theme>('dark')

// 使用断言创建 {} const context u003d react createContext({} as ContextState);

常量 sampleAppContext: TeemeContext u003d 'light';

导出 const App u003d () u003d> (

<AppCtx.Provider valueu003d{sampleAppContext}>...</AppCtx.Provider>

);

// 如果要创建默认值null或者undefined,可以react createContext<string>(undefined!),否则在使用时间

// 会报没有相关的api可以调用,但是这样会失去类型安全,或者可以用一个helper函数来帮助我们创建,这样我们就不用考虑undeined了

// 情况

函数 createCtx<A 扩展 {} |空>(){

const ctx u003d React.createContext<A |未定义>(未定义);

函数 useCtx() {

常量 c u003d React.useContext(ctx);

如果(c u003du003du003d 未定义)

throw new Error("useCtx 必须在一个有值的 Provider 内");

返回 c;

}

返回 [useCtx, ctx.Provider] 作为 const; // 'as const' 使 TypeScript 推断出一个元组

}

// 用法:

// 我们仍然需要指定一个类型,但没有默认值!

导出 const [useCurrentUserName, CurrentUserProvider] u003d createCtx<string>();

功能热情问候(){

常量 currentUser u003d useCurrentUserName();

返回 <div>你好 {currentUser.toUpperCase()}!</div>;

}

函数应用程序() {

返回 (

<CurrentUserProvider valueu003d"安德斯">

<热情的问候/>

</CurrentUserProvider>

);

}

//

// 集成useContext、createContext和useState

导出函数 createCtx<A>(defaultValue: A) {

类型 UpdateType u003d React.Dispatch<

React.SetStateAction<typeof defaultValue>

;

const defaultUpdate: UpdateType u003d () u003d> defaultValue;

const ctx u003d React.createContext({

状态:默认值,

更新:默认更新,

});

功能提供者(道具:React.PropsWithChildren<{}>){

常量[状态,更新] u003d React.useState(defaultValue);

return <ctx.Provider valueu003d{{ state, update }} {...props} />;

}

返回 [ctx, Provider] 作为 const; // 或者,[typeof ctx, typeof Provider]

}

// 用法

const [ctx, TextProvider] u003d createCtx("someText");

导出常量 TextContext u003d ctx;

导出函数 App() {

返回 (

<文本提供者>

<组件/>

</TextProvider>

);

}

导出函数组件() {

常量 { 状态,更新 } u003d React.useContext(TextContext);

返回 (

<标签>

{状态}

<input typeu003d"text" onChangeu003d{(e) u003d> update(e.target.value)} />

</标签>

);

}

//更好的createContextApi

https://gist.github.com/sw-yx/f18fe6dd4c43fddb3a4971e80114a052

14.使用ImperativeHandle,forwardRef

导出接口 MyInputHandles {

焦点():无效;

}

常量 MyInput: RefForwardingComponent<MyInputHandles, MyInputProps> u003d (props, ref) u003d> {

常量 inputRef u003d useRef<HTMLInputElement>(null);

useImperativeHandle(ref, () u003d>({

焦点:() u003d> {

if(inputRef.current) {

inputRef.current.focus();

}

}

}))

返回 <输入{...props} refu003d{inputRef}>

}

导出默认 forwardRef(MyInput)

  1. 反应。为了更好地引用组件中的状态,您可以使用 react Component < mystate > 和 state:MyState {} 进行注释

  2. props 注解不需要标为ReadOnly。因为 ReadOnly 在添加到泛型组件时会自动添加

3.类属性

指针:数字

1.getDerivedStateFromProps

静态 getDerivedStateFromProps(props:Props, state:State): 部分<State> |无效的 {

}

1.当需要函数的返回值来判断状态时可以使用ReturnType

静态 getDerivedStateFromProps(props:Props, state:State): 部分<State> |无效的 {

}

1.在ts中,不用写defaultProps

21.如何优雅地提取组件的props

const GreetComponent u003d ({ name, age }: {name:string, age:25}) u003d> (

<div>{`Hello, my name is ${name}, ${age}`}</div>

);

类型 ComponentProps<T> u003d T 扩展

| React.ComponentType<推断 P>

| React.Component<推断 P>

? JSX.LibraryManagedAttributes<T, P>

: 从不;

const TestComponent u003d (props: ComponentProps<typeof GreetComponent>) u003d> {

返回 <h1 />;

};

一、react中常见的ts类型

类型 AppProps u003d {

消息:字符串;

数:数;

禁用:布尔值;

/** 一个类型的数组! */

名称:字符串[];

/** 字符串文字,用于指定精确的字符串值,并使用联合类型将它们连接在一起 */

状态:“等待” | “成功”;

/** 任何对象,只要你不使用它的属性(不常见,但用作占位符)*/

对象:对象;

obj2:{}; // 几乎和`object`一样,和`Object`完全一样

/** 具有任意数量属性的对象(首选)*/

鹈鹕:{

id:字符串;

标题:字符串;

};

/** 对象数组! (常见的) */

objArr:{

id:字符串;

标题:字符串;

}[];

/** 具有任意数量的相同类型属性的 dict 对象 */

字典 1:{

[键:字符串]:MyTypeHere;

};

dict2: 记录<string, MyTypeHere>; // 相当于 dict1

/** 任何函数,只要你不调用它(不推荐)*/

onSomething:函数;

/** 不接受或不返回任何内容的函数(非常常见)*/

onClick: () u003d> 无效;

/** 带有命名道具的函数(非常常见)*/

onChange: (id: number) u003d> 无效;

/** 接受事件的替代函数类型语法(非常常见)*/

onClick(事件:React.MouseEvent<HTMLButtonElement>):无效;

/** 一个可选的道具(非常常见!)*/

可选?:可选类型;

};

  1. react中的评论

类型 AppProps u003d {

消息:字符串;

数:数;

禁用:布尔值;

/** 一个类型的数组! */

名称:字符串[];

/** 字符串文字,用于指定精确的字符串值,并使用联合类型将它们连接在一起 */

状态:“等待” | “成功”;

/** 任何对象,只要你不使用它的属性(不常见,但用作占位符)*/

对象:对象;

obj2:{}; // 几乎和`object`一样,和`Object`完全一样

/** 具有任意数量属性的对象(首选)*/

鹈鹕:{

id:字符串;

标题:字符串;

};

/** 对象数组! (常见的) */

objArr:{

id:字符串;

标题:字符串;

}[];

/** 具有任意数量的相同类型属性的 dict 对象 */

字典 1:{

[键:字符串]:MyTypeHere;

};

dict2: 记录<string, MyTypeHere>; // 相当于 dict1

/** 任何函数,只要你不调用它(不推荐)*/

onSomething:函数;

/** 不接受或不返回任何内容的函数(非常常见)*/

onClick: () u003d> 无效;

/** 带有命名道具的函数(非常常见)*/

onChange: (id: number) u003d> 无效;

/** 接受事件的替代函数类型语法(非常常见)*/

onClick(事件:React.MouseEvent<HTMLButtonElement>):无效;

/** 一个可选的道具(非常常见!)*/

可选?:可选类型;

};

24\。接口和类型别名的区别

类型别名与接口非常相似,在许多情况下您可以自由选择它们。界面中几乎所有功能都可用。关键区别在于您不能重新打开类型以添加新属性和始终可扩展的接口。

25\。当你想使用 getDerivedStateFromProps 的返回值作为构建的状态注解时

// 1. 一般情况

类 Comp 扩展 React.Component<

道具,

ReturnType<typeof Comp["getDerivedStateFromProps"]>

{

静态 getDerivedStateFromProps(props: Props) {}

}

// 2. 返回函数

类型 CustomValue u003d 任何;

界面道具 {

propA:自定义值;

}

接口定义状态 {

其他状态字段:字符串;

}

type State u003d DefinedState & ReturnType<typeof transformPropsToState>;

函数 transformPropsToState(props: 道具) {

返回{

savedPropA: props.propA, // 保存以备记忆

派生状态:props.propS,

};

}

类 Comp 扩展 React.PureComponent<Props, State> {

构造函数(道具:道具){

超级(道具);

this.state u003d {

其他状态字段:“123”,

...transformPropsToState(道具),

};

}

静态 getDerivedStateFromProps(道具:道具,状态:状态){

if (isEqual(props.propA, state.savedPropA)) 返回空值;

返回 transformPropsToState(props);

}

}

  1. 表单事件

// 如果不考虑性能,可以使用内联处理,会自动正确生成注解

常量 el u003d (

<button onClicku003d(eu003d>{

//...

})/>

)

// 如果需要在外部定义类型

handlerChange u003d (e: React.FormEvent<HTMLInputElement>): void u003d> {

//

}

// 如果在 u003d 符号的左侧进行注释

handlerChange: React.ChangeEventHandler<HTMLInputElement> u003d e u003d> {

//

}

// 如果表单中有onSubmit事件,则react Syntheticevent.如果有自定义类型,可以使用类型断言

<表格

参考u003d{formRef}

onSubmitu003d{(e: React.SyntheticEvent) u003d> {

e.preventDefault();

const target u003d e.target as typeof e.target & {

电子邮件:{值:字符串};

密码:{值:字符串};

};

常量电子邮件 u003d target.email.value; // 类型检查!

// 等等...

}}

<div>

<标签>

电子邮件:

<input typeu003d"email" nameu003d"email" />

</标签>

</div>

<div>

<input typeu003d"submit" valueu003d"登录" />

</div>

</form>

1.事件类型列表

AnimationEvent : css 动画事件

ChangeEvent:<input>,<select>和<textarea>元素变化事件

ClipboardEvent:复制、粘贴、剪切事件

CompositionEvent:用户间接输入文本时发生的事件(例如根据浏览器和PC如果要在美式键盘上输入日文,可能会出现带有附加字符的弹窗)

DragEvent:设备上的拖放和交互事件

FocusEvent:元素获取事件的焦点

FormEvent:当表单元素获得或失去焦点/值更改/表单提交事件

InvalidEvent:当输入的有效性限制失败时触发(例如<input typeu003d"number" maxu003d"10">,有人会插入数字20)

KeyboardEvent:键盘输入事件

MouseEvent:鼠标移动事件

PointerEvent: Mouse, pen/Stylus, touch screen)由于交互而发生的事件

TouchEvent:用户与触摸设备交互时发生的事件

TransitionEvent: CSS Transition,浏览器支持度不高

UIEvent:鼠标、触摸和指针事件的基本事件。

WheelEvent:滚动鼠标滚轮或类似的输入设备

SyntheticEvent:上述所有事件的基础事件。事件类型不确定时是否应该使用

// 因为InputEvent在不同的浏览器支持不同,所以可以用KeyboardEvent代替

28.createRef 和 forwardRef

类 CssThemeProvider 扩展 React.PureComponent<Props> {

私有 rootRef u003d React.createRef<HTMLDivElement>(); // 像这样

渲染() {

返回 <div refu003d{this.rootRef}>{this.props.children}</div>;

}

}

// 这样的forwardRef是可变的,必要时可以赋值

类型道具 u003d { 孩子:React.ReactNode;类型:“提交”| “按钮” };

导出类型 Ref u003d HTMLButtonElement;

导出 const FancyButton u003d React.forwardRef<Ref, Props>((props, ref) u003d> (

<button refu003d{ref} classNameu003d"MyClassName" typeu003d{props.type}>

{props.children}

</按钮>

));

// 如果你希望它是不可变的

// 类型 Ref u003d HTMLButtonElement

// (props, ref: React.Ref<Ref>) u003d>

// 如果要获取forwardRef组件的props,可以使用compoentPropsWithRef

29.ReactDOM.createPortal

// 类

const modalRoot u003d document.getElementById("modal-root") as HTMLElement;

// 假设你的 html 文件中有一个 id 为 'modal-root' 的 div;

导出类 Modal 扩展 React.Component {

el: HTMLElement u003d document.createElement("div");

组件DidMount() {

modalRoot.appendChild(this.el);

}

组件WillUnmount() {

modalRoot.removeChild(this.el);

}

渲染() {

return ReactDOM.createPortal(this.props.children, this.el);

}

}

// 钩子

导入反应,{ useEffect,useRef } 从“反应”;

从“react-dom”导入 { createPortal };

const modalRoot u003d document.querySelector("#modal-root") as HTMLElement;

const 模态:React.FC<{}> u003d ({ children }) u003d> {

常量 el u003d useRef(document.createElement("div"));

使用效果(() u003d> {

// 如果 CRA 抛出有关 react-hooks/exhaustive-deps 的错误,请使用此选项

常量电流 u003d el.current;

// 我们假设 `modalRoot`以 '!' 存在

modalRoot!.appendChild(current);

return () u003d> void modalRoot!.removeChild(current);

}, []);

return createPortal(children, el.current);

};

导出默认模态;

  1. 错误处理

//选项1:使用react错误边界

//option2:自定义边界组件

从 "react" 导入 React, { Component, ErrorInfo, ReactNode };

界面道具 {

孩子:反应节点;

}

界面状态 {

hasError:布尔值;

}

类 ErrorBoundary 扩展 Component<Props, State> {

公共状态:状态 u003d {

有错误:假

};

公共静态 getDerivedStateFromError(_: 错误): 状态 {

// 更新状态,以便下一次渲染将显示回退 UI。

返回 { hasError: true };

}

公共组件DidCatch(错误:错误,错误信息:错误信息){

console.error("未捕获的错误:", error, errorInfo);

}

公共渲染() {

if (this.state.hasError) {

return <h1>Sorry.. 出现错误</h1>;

}

返回 this.props.children;

}

}

导出默认错误边界;

31\。关联类型的缺点是在对象的关联中无法准确区分对象

界面管理员 {

角色:字符串;

}

界面用户 {

电子邮件:字符串;

}

// 方法一:使用 `in`关键字

功能重定向(用户:管理员 | 用户){

if(用户中的“角色”){

// 自 TS 2.7+ 起使用 `in`运算符作为类型保护

routeToAdminPage(user.role);

} 其他 {

routeToHomePage(user.email);

}

}

// 方法 2:自定义类型保护,在旧 TS 版本或 `in`不够的地方做同样的事情

功能是管理员(用户:管理员 | 用户):用户是管理员 {

return (user as any).role !u003du003d undefined;

}

// 方法 ...: typeOf 和 instanceof 也提供方便的类型保护

1.期待已久的非空断言排序规则使用(最好实际处理空值,少用这种方法)

element.parentNode!.removeChild(元素); // !期间之前

myFunction(document.getElementById(dialog.id!)!); // !物业访问后

让用户ID!:字符串; // 明确的赋值断言...小心!

1.创建带有符号的识别ID注释

type OrderID u003d string & { readonly brand: unique symbol };

type UserID u003d string & { readonly brand: unique symbol };

类型 ID u003d 订单 ID |用户身份;

函数 OrderID(id: string) {

将 id 作为 OrderID 返回;

}

功能用户ID(ID:字符串){

返回 id 作为 UserID;

}

函数 queryForUser(id: UserID) {

// ...

}

queryForUser(OrderID("foobar")); // 错误,“OrderID”类型的参数不可分配

// 到“UserID”类型的参数

// unique 是一个关键字

// 唯一的 T(其中 t 是任何类型)允许在任何地方使用类型,并且名义上用标签标记 T,以便来自该位置的 t 只能分配给结果类型。

// 这是每个交易品种的独特结构。然后通过交集将其混合到参数类型中以生成所有有用的关系

// 唯一符号的当前行为优先于语法上完全唯一的符号。但是,如果实际需要符号的名义子类,则可以编写

// Unique (symbol) 获得一个名义上的品牌符号类型(或符号 & unique unknown - 这完全一样)。只要

// 符号的行为类似于锁定在特定声明中的符号,因此它们在收缩和控制流时具有特殊功能。标称品牌类型使用更灵活,

// 但是没有带有强控制流链接的主机声明

// https://github.com/microsoft/TypeScript/pull/33038

// 示例:

// 类型 NormalizedPath u003d 唯一字符串;

// 类型 AbsolutePath u003d 唯一字符串;

// type Normalized Absolute Path u003d Normalized Path and Absolute Path;

// 声明函数 isNormalizedPath(x: string): x is NormalizedPath;

// 声明函数 isAbsolutePath(x: string): x is AbsolutePath;

// 声明函数 consumeNormalizedAbsolutePath(x: NormalizedAbsolutePath): void;

// 常量 p u003d "/a/b/c";

// if (isNormalizedPath(p)) {

// if (isAbsolutePath(p)) {

// consumeNormalizedAbsolutePath(p);

// }

// }

33.重载功能

// 1。

function pickCard(x: { 花色: string; card: number }[]): number;

function pickCard(x: number): { 花色: string;卡号 };

功能pickCard(x):任何{

// 组合签名的实现

// ...

}

// 2。

键入pickCard u003d {

(x: { 花色: 串; 牌: 号码 }[]): 号码;

(x: number): { 花色: string;卡号 };

// 这种形式不需要组合签名

// 你也可以在这里输入函数的静态属性,例如 `pickCard.wasCalled`

};

34\。获取组件的 props 类型,使用 react ComponentProps<typeof Button>

35\。 interface 和 typeof 定义的 {a:1,b:2} 等对象有不同的类型。前者不仅检查值的类型,还检查值

36.js 自动转换ts的工具

dts-gen

类型统计

类型向导

js 到 ts 转换器

Airbnb 转换中使用的 TS-migrate

37\。用户自定义挂钩类型定义规范

声明模块“使用无类型挂钩”{

export interface InputProps { ... } // prop 的类型声明

export interface ReturnProps { ... } // 返回道具的类型声明

导出默认函数 useUntypedHook(

道具:输入道具

// ...

): 返回道具;

}

39\。为类创建类型定义

从“react”导入 * 作为 React;

声明类 SimpleSelect 扩展 React.Component<SimpleSelectProps, any> {}

导出接口 SimpleSelectProps {

自动对焦?:布尔值;

cancelKeyboardEventOnSelection?: 布尔值;

类名?:字符串;

createFromSearch?(items: OptionValue[], search: string): OptionValue;

defaultValue?:选项值;

分隔符?:[任何];

禁用?:布尔值;

// ...

}

导出默认 SimpleSelect;

  1. 内置类型

ConstructorParameters:类构造函数参数类型的元组

排除:从一种类型中排除另一种类型

提取:选择可以分配给其他类型的子类型

InstanceType:从新的类构造函数中获取的实例类型

NonNullable:从类型中排除 null 和 undefined

参数:函数参数类型的元组

部分:使对象中的所有属性可选

只读:将对象中的所有属性设置为只读

ReadonlyArray:创建给定类型的不可变数组

Pick:对象类型的子类型,包含其键的子集

记录:从键类型到值类型的映射

必需:使对象中的所有属性都是必需的

ReturnType:函数的返回类型

41\。如果你在库的官方类型中遇到 bug,你可以将它们复制到本地,并通过“paths”字段告诉 TypeScript 使用你的本地版本。在你的 tsconfig json

{

“编译器选项”:{

“路径”:{

"mobx-react": ["../typings/modules/mobx-react"]

}

}

}

Logo

React社区为您提供最前沿的新闻资讯和知识内容

更多推荐