Практика React + TypeScript

внешний интерфейс React.js

❗️ Готовое знание:

  • Познакомьтесь с React

Этот документ относится к последней версии TypeScript

Как представить React

import * as React from 'react'

import * as ReactDOM from 'react-dom'

этот способ ссылкидоказалсамый надежный путь,Рекомендуемое использование.

И еще один способ процитировать:

import React from 'react'

import ReactDOM from 'react-dom'

Необходимо добавить дополнительную конфигурацию: «allowSyntheticDefaultImports»: true

Как объявить функциональные компоненты

Несколько способов объявить

Первый: также сравнитьрекомендоватьодин, используяReact.FunctionComponent, в краткой форме:React.FC:



// Great

type AppProps = {

  message: string

}



const App: React.FC<AppProps> = ({ message, children }) => (

  <div>

    {message}

    {children}

  </div>

)

Объявляйте функциональные компоненты с помощью React.FC иОбычное заявлениетак же какPropsWithChildrenРазница в следующем:

  • React.FC явно определяет тип возвращаемого значения, другие способы выводятся неявно
  • React.FC обеспечивает проверку типов и автодополнение для статических свойств: displayName, propTypes, defaultProps.

  • React.FC предоставляет неявный тип для дочерних элементов (ReactElement | null), но в настоящее время указанный тип существует.некоторые вопросы(вопрос)

Например, при следующем использовании React.FC сообщит об ошибке типа:



const App: React.FC = props => props.children



const App: React.FC = () => [1, 2, 3]



const App: React.FC = () => 'hello'

Решение:



const App: React.FC<{}> = props => props.children as any

const App: React.FC<{}> = () => [1, 2, 3] as any

const App: React.FC<{}> = () => 'hello' as any



// 或者



const App: React.FC<{}> = props => (props.children as unknown) as JSX.Element

const App: React.FC<{}> = () => ([1, 2, 3] as unknown) as JSX.Element

const App: React.FC<{}> = () => ('hello' as unknown) as JSX.Element

Как правило, используйтеReact.FCМетод объявления является самым простым и эффективным, и рекомендуется использовать его, если есть проблема несовместимости типов, рекомендуется использоватьСледующие два способа:

Второе: использоватьPropsWithChildren, этот метод может избавить вас от частого определения типа дочерних элементов и автоматически установить тип дочерних элементов в ReactNode:



type AppProps = React.PropsWithChildren<{ message: string }>



const App = ({ message, children }: AppProps) => (

  <div>

    {message}

    {children}

  </div>

)

Третий тип: прямое утверждение:



type AppProps = {

  message: string

  children?: React.ReactNode

}



const App = ({ message, children }: AppProps) => (

  <div>

    {message}

    {children}

  </div>

)

Hooks

useState<T>

В большинстве случаев TS автоматически сделает это за вас.stateтип:



// `val`会推导为boolean类型, toggle接收boolean类型参数

const [val, toggle] = React.useState(false)



// obj会自动推导为类型: {name: string}

const [obj] = React.useState({ name: 'sj' })



// arr会自动推导为类型: string[]

const [arr] = React.useState(['One', 'Two'])

Используйте выведенный тип в качестве интерфейса/типа:



export default function App() {

  // user会自动推导为类型: {name: string}

  const [user] = React.useState({ name: 'sj', age: 32 })

  const showUser = React.useCallback((obj: typeof user) => {

    return `My name is ${obj.name}, My age is ${obj.age}`

  }, [])



  return <div className="App">用户: {showUser(user)}</div>

}

Однако некоторые начальные значения состояния пусты (null), тип должен быть объявлен явно:



type User = {

  name: string

  age: number

}



const [user, setUser] = React.useState<User | null>(null)

useRef<T>

Когда начальное значениеnull, есть два способа его создания:



const ref1 = React.useRef<HTMLInputElement>(null)

const ref2 = React.useRef<HTMLInputElement | null>(null)

Разница между ними в том, что:

  • ref1.current первого способатолько для чтения, и может быть передан во встроенный атрибут ref для привязки элементов DOM.;
  • ref2.current второго способаПеременная(аналогично объявлению переменной-члена класса)


const ref = React.useRef(0)



React.useEffect(() => {

  ref.current += 1

}, [])

При использовании этих двух методов необходимо проверить оба типа:



const onButtonClick = () => {

  ref1.current?.focus()



  ref2.current?.focus()

}

В некоторых случаях проверку типов можно исключить, добавив! утверждение,Не рекомендуется:



// Bad

function MyComponent() {

  const ref1 = React.useRef<HTMLDivElement>(null!)

  React.useEffect(() => {

    //  不需要做类型检查,需要人为保证ref1.current.focus一定存在

    doSomethingWith(ref1.current.focus())

  })

  return <div ref={ref1}> etc </div>

}

useEffect

useEffectСледует отметить, что возвращаемое значение функции обратного вызова может быть только функцией илиundefined



function App() {

  // undefined作为回调函数的返回值

  React.useEffect(() => {

    // do something...

  }, [])



  // 返回值是一个函数

  React.useEffect(() => {

    // do something...

    return () => {}

  }, [])

}

useMemo<T> / useCallback<T>

useMemoа такжеuseCallbackмогут вывести их тип непосредственно из значения, которое они возвращают

useCallbackПараметр должен быть типа, иначе ts не сообщит об ошибке, по умолчанию указано какany



const value = 10

// 自动推断返回值为 number

const result = React.useMemo(() => value * 2, [value])



// 自动推断 (value: number) => number

const multiply = React.useCallback((value: number) => value * multiplier, [

  multiplier,

])

Также поддерживает входящие дженерики,useMemoОбщий тип указывает тип возвращаемого значения,useCallbackОбщий тип указывает тип параметра



// 也可以显式的指定返回值类型,返回值不一致会报错

const result = React.useMemo<string>(() => 2, [])

// 类型“() => number”的参数不能赋给类型“() => string”的参数。



const handleChange = React.useCallback<

  React.ChangeEventHandler<HTMLInputElement>

>(evt => {

  console.log(evt.target.value)

}, [])

Пользовательские крючки

Следует отметить, что если возвращаемое значение пользовательского хука равнотип массива, TS автоматически выводится какUnionТип, и что нам действительно нужно, так это конкретный тип каждого элемента в массиве, который нужно добавить вручную.const утверждениеОбрабатывать:



function useLoading() {

  const [isLoading, setState] = React.useState(false)

  const load = (aPromise: Promise<any>) => {

    setState(true)

    return aPromise.then(() => setState(false))

  }



  // 实际需要: [boolean, typeof load] 类型

  // 而不是自动推导的:(boolean | typeof load)[]

  return [isLoading, load] as const

}

При использованииconstУтверждают, что обнаруженывопрос, вы также можете напрямую определить тип возвращаемого значения:



export function useLoading(): [

  boolean,

  (aPromise: Promise<any>) => Promise<any>

] {

  const [isLoading, setState] = React.useState(false)

  const load = (aPromise: Promise<any>) => {

    setState(true)

    return aPromise.then(() => setState(false))

  }

  return [isLoading, load]

}

Если у вас есть много пользовательских хуков, вот удобный служебный метод для обработки возвращаемых значений кортежа:



function tuplify<T extends any[]>(...elements: T) {

  return elements

}



function useLoading() {

  const [isLoading, setState] = React.useState(false)

  const load = (aPromise: Promise<any>) => {

    setState(true)

    return aPromise.then(() => setState(false))

  }



  // (boolean | typeof load)[]

  return [isLoading, load]

}



function useTupleLoading() {

  const [isLoading, setState] = React.useState(false)

  const load = (aPromise: Promise<any>) => {

    setState(true)

    return aPromise.then(() => setState(false))

  }



  // [boolean, typeof load]

  return tuplify(isLoading, load)

}

Свойство по умолчанию defaultProps

Большинство статейНе рекомендуетсяиспользовать defaultProps,Связанные обсуждения могут**Ссылка на ссылку**

Рекомендуемый способ: использоватьЗначение параметра по умолчаниюзаменитьСвойства по умолчанию:



type GreetProps = { age?: number }

const Greet = ({ age = 21 }: GreetProps) => {

  /* ... */

}

Тип DEFAULTPROPS

TypeScript3.0+Это было большое улучшение по сравнению с атрибутами по умолчанию для вывода типов, хотя все жеЕсть некоторые граничные случаи, которые все еще проблематичны,Не рекомендуется, если вам нужно использовать сцену, вы можете обратиться к следующим методам:



type IProps = {

  name: string

}

const defaultProps = {

  age: 25,

}



// 类型定义

type GreetProps = IProps & typeof defaultProps



const Greet = (props: GreetProps) => <div></div>

Greet.defaultProps = defaultProps

// 使用

const TestComponent = (props: React.ComponentProps<typeof Greet>) => {

  return <h1 />

}

const el = <TestComponent name="foo" />

Types or Interfaces

В ежедневной разработке реакцииinterfaceа такжеtypeСценарии использования очень похожи

implementsа такжеextendsСтатические операции, случай, когда есть одна реализация или другая, не разрешены, поэтомуИспользование типов объединения не поддерживается:



class Point {

  x: number = 2

  y: number = 3

}



interface IShape {

  area(): number

}



type Perimeter = {

  perimeter(): number

}



type RectangleShape = (IShape | Perimeter) & Point



class Rectangle implements RectangleShape {

  // 类只能实现具有静态已知成员的对象类型或对象类型的交集。

  x = 2

  y = 3

  area() {

    return this.x + this.y

  }

}



interface ShapeOrPerimeter extends RectangleShape {}

// 接口只能扩展使用静态已知成员的对象类型或对象类型的交集

Использовать тип или интерфейс?

Существует несколько общих правил:

  • Используйте при определении общедоступного API (например, при редактировании библиотеки).interface, что упрощает пользователям наследование интерфейса
  • При определении свойств компонента (Props) и состояний (State) рекомендуется использоватьtype,потому чтоtypeболее ограничительный

interfaceа такжеtypeДве разные концепции в ts, но в основном используемые в Reactcaseсередина,interfaceа такжеtypeВы можете достичь такими же функциональными эффектами,typeа такжеСамое большое отличие интерфейсаДа:

  • typeТипы нельзя редактировать дважды, в то время какinterfaceможно расширить в любой момент


interface Animal {

  name: string

}



// 可以继续在原有属性基础上,添加新属性:color

interface Animal {

  color: string

}



/********************************/



type Animal = {

  name: string

}



// type类型不支持属性扩展

// Error: Duplicate identifier 'Animal'

type Animal = {

  color: string

}

Получить неэкспортированный тип

В некоторых сценариях, когда мы вводим стороннюю библиотеку, мы обнаружим, что компонент, который мы хотим использовать, не экспортирует тип параметра компонента или тип возвращаемого значения, который нам нужен.В это время мы можем получить желаемый тип через ComponentProps/ Тип возврата.



// 获取参数类型

import { Button } from 'library' // 但是未导出props type

type ButtonProps = React.ComponentProps<typeof Button> // 获取props

type AlertButtonProps = Omit<ButtonProps, 'onClick'> // 去除onClick

const AlertButton: React.FC<AlertButtonProps> = props => (

  <Button onClick={() => alert('hello')} {...props} />

)


// 获取返回值类型

function foo() {

  return { baz: 1 }

}



type FooReturn = ReturnType<typeof foo> // { baz: number }

Props

Обычно мы используемtypeопределятьProps, чтобы улучшить ремонтопригодность и читабельность кода, мы надеемся добавить четкие комментарии в ежедневный процесс разработки.

Сейчас есть такойtype



type OtherProps = {

  name: string

  color: string

}

В процессе использования соответствующий тип наведения будет отображаться следующим образом



// type OtherProps = {

//   name: string;

//   color: string;

// }

const OtherHeading: React.FC<OtherProps> = ({ name, color }) => (

  <h1>My Website Heading</h1>

)

Добавьте относительно подробные комментарии, это будет понятнее при использовании, нужно обратить внимание,Аннотацию нужно использовать /**/ , // Не распознается vscode



// Great

/**

 * @param color color

 * @param children children

 * @param onClick onClick

 */

type Props = {

  /** color */

  color?: string

  /** children */

  children: React.ReactNode

  /** onClick */

  onClick: () => void

}



// type Props

// @param color — color

// @param children — children

// @param onClick — onClick

const Button: React.FC<Props> = ({ children, color = 'tomato', onClick }) => {

  return (

    <button style={{ backgroundColor: color }} onClick={onClick}>

      {children}

    </button>

  )

}

Обычно используемые типы реквизита ts

базовый тип свойства



type AppProps = {

  message: string

  count: number

  disabled: boolean

  /** array of a type! */

  names: string[]

  /** string literals to specify exact string values, with a union type to join them together */

  status: 'waiting' | 'success'

  /** 任意需要使用其属性的对象(不推荐使用,但是作为占位很有用) */

  obj: object

  /** 作用和`object`几乎一样,和 `Object`完全一样 */

  obj2: {}

  /** 列出对象全部数量的属性 (推荐使用) */

  obj3: {

    id: string

    title: string

  }

  /** array of objects! (common) */

  objArr: {

    id: string

    title: string

  }[]

  /** 任意数量属性的字典,具有相同类型*/

  dict1: {

    [key: string]: MyTypeHere

  }

  /** 作用和dict1完全相同 */

  dict2: Record<string, MyTypeHere>

  /** 任意完全不会调用的函数 */

  onSomething: Function

  /** 没有参数&返回值的函数 */

  onClick: () => void

  /** 携带参数的函数 */

  onChange: (id: number) => void

  /** 携带点击事件的函数 */

  onClick(event: React.MouseEvent<HTMLButtonElement>): void

  /** 可选的属性 */

  optional?: OptionalType

}

Общие типы свойств React



export declare interface AppBetterProps {

  children: React.ReactNode // 一般情况下推荐使用,支持所有类型 Great

  functionChildren: (name: string) => React.ReactNode

  style?: React.CSSProperties // 传递style对象

  onChange?: React.FormEventHandler<HTMLInputElement>

}



export declare interface AppProps {

  children1: JSX.Element // 差, 不支持数组

  children2: JSX.Element | JSX.Element[] // 一般, 不支持字符串

  children3: React.ReactChildren // 忽略命名,不是一个合适的类型,工具类类型

  children4: React.ReactChild[] // 很好

  children: React.ReactNode // 最佳,支持所有类型 推荐使用

  functionChildren: (name: string) => React.ReactNode // recommended function as a child render prop type

  style?: React.CSSProperties // 传递style对象

  onChange?: React.FormEventHandler<HTMLInputElement> // 表单事件, 泛型参数是event.target的类型

}

Forms and Events

onChange

changeСобытия, есть два метода, которые определяют тип параметра.

Первый метод использует предполагаемую сигнатуру метода (например:React.FormEvent <HTMLInputElement> :пустота)



import * as React from 'react'



type changeFn = (e: React.FormEvent<HTMLInputElement>) => void



const App: React.FC = () => {

  const [state, setState] = React.useState('')



  const onChange: changeFn = e => {

    setState(e.currentTarget.value)

  }



  return (

    <div>

      <input type="text" value={state} onChange={onChange} />

    </div>

  )

}

Второй метод заставляет использовать@types / reactПредоставленный тип делегата, оба метода приемлемы.



import * as React from 'react'



const App: React.FC = () => {

  const [state, setState] = React.useState('')



  const onChange: React.ChangeEventHandler<HTMLInputElement> = e => {

    setState(e.currentTarget.value)

  }

  return (

    <div>

      <input type="text" value={state} onChange={onChange} />

    </div>

  )

}

onSubmit

Если вас не волнует тип события, вы можете использовать его напрямуюReact.SyntheticEvent, если целевая форма имеет настраиваемый именованный ввод, к которому вы хотите получить доступ, вы можете использовать расширение типа



import * as React from 'react'



const App: React.FC = () => {

  const onSubmit = (e: React.SyntheticEvent) => {

    e.preventDefault()

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

      password: { value: string }

    } // 类型扩展

    const password = target.password.value

  }

  return (

    <form onSubmit={onSubmit}>

      <div>

        <label>

          Password:

          <input type="password" name="password" />

        </label>

      </div>

      <div>

        <input type="submit" value="Log in" />

      </div>

    </form>

  )

}

Operators

Обычно используемые операторы, часто используемые для оценки типа

  • typeof и instanceof: для различия типов
  • keyof: получить ключ объекта

  • O[K]: поиск свойства

  • [K in O]: тип сопоставления

  • + или - или только для чтения или ?: сложение, вычитание, только для чтения и необязательные модификаторы

  • x Y : Z: условный тип для универсальных типов, псевдонимов типов, типов параметров функций.

  • !: Нулевое утверждение для типов, допускающих значение NULL

  • as: утверждение типа

  • is: type guard для возвращаемого типа функции

Tips

Доступ к типам свойств компонентов с использованием типов поиска

Уменьшить по типу поискаtypeвторостепенный экспорт, если это необходимо для обеспечения сложныхtype, который следует извлечь в файл, экспортируемый как общедоступный API.

Теперь у нас есть компонент Counter, для которого требуется имя требуемого параметра:



// counter.tsx

import * as React from 'react'

export type Props = {

  name: string

}

const Counter: React.FC<Props> = props => {

  return <></>

}

export default Counter

В других компонентах, которые ссылаются на него, у нас есть два способа получить тип параметра Counter.

Первый черезtypeofоператор (рекомендовать)



// Great

import Counter from './d-tips1'

type PropsNew = React.ComponentProps<typeof Counter> & {

  age: number

}



const App: React.FC<PropsNew> = props => {

  return <Counter {...props} />

}

export default App

Второй - путем экспорта в исходный компонент



import Counter, { Props } from './d-tips1'



type PropsNew = Props & {

  age: number

}



const App: React.FC<PropsNew> = props => {

  return (

    <>

      <Counter {...props} />

    </>

  )

}

export default App

Не используйте объявления функций в типе или интерфейсе

Для согласованности все члены типа/интерфейса определяются с помощью одного и того же синтаксиса.

--strictFunctionTypesБолее строгая проверка типов применяется при сравнении типов функций, но строгая проверка не действует в первом объявлении.

✅

interface ICounter {

  start: (value: number) => string

}



❌

interface ICounter1 {

  start(value: number): string

}



🌰

interface Animal {}

interface Dog extends Animal {

  wow: () => void

}

interface Comparer<T> {

  compare: (a: T, b: T) => number

}

declare let animalComparer: Comparer<Animal>

declare let dogComparer: Comparer<Dog>

animalComparer = dogComparer // Error

dogComparer = animalComparer // Ok



interface Comparer1<T> {

  compare(a: T, b: T): number

}

declare let animalComparer1: Comparer1<Animal>

declare let dogComparer1: Comparer1<Dog>

animalComparer1 = dogComparer // Ok

dogComparer1 = animalComparer // Ok

обработка событий

Мы часто используем обработчики событий при регистрации событийeventобъект события, например, при использовании событий мыши мы передаемclientX,clientYчтобы получить координаты указателя.

Вы можете подумать, что прямоeventУстановить какanytype, но тогда мы теряем смысл статической проверки нашего кода.



function handleEvent(event: any) {

  console.log(event.clientY)

}

Только представьте, когда мы регистрируемTouchсобытие, затем ошибочно переданное в обработчик событияeventобъект, чтобы получить егоclientYстоимость имущества, здесь мы поставилиeventУстановить какanyтипа, в результате чегоTypeScriptОн не выдает нам ошибок при компиляции, при переходеevent.clientYВозникла проблема при доступе, т.к.Touchмероприятиеeventобъект неclientYэто свойство.

пройти черезinterfaceправильноeventК счастью, писать объявление типа объекта — пустая трата времени.ReactФайл объявлений содержит объявление типа для объекта Event.

Тип объекта события события

  • ClipboardEvent Объект события буфера обмена
  • DragEvent объект события перетаскивания

  • ChangeEvent Изменить объект события

  • KeyboardEvent объект события клавиатуры

  • MouseEvent объект события мыши

  • TouchEvent сенсорный объект события

  • WheelEvent Объект времени колеса

  • AnimationEvent объект события анимации

  • TransitionEvent объект события перехода

тип обработчика событий

Когда мы определяем обработчик событий, есть ли более удобный способ определить тип его функции? Ответ заключается в использованииReactпредоставленный файл декларацииEventHandlerПсевдонимы типов через разные событияEventHandlerвведите псевдоним, чтобы определить тип обработчика событий



type EventHandler<E extends React.SyntheticEvent<any>> = {

  bivarianceHack(event: E): void

}['bivarianceHack']

type ReactEventHandler<T = Element> = EventHandler<React.SyntheticEvent<T>>

type ClipboardEventHandler<T = Element> = EventHandler<React.ClipboardEvent<T>>

type DragEventHandler<T = Element> = EventHandler<React.DragEvent<T>>

type FocusEventHandler<T = Element> = EventHandler<React.FocusEvent<T>>

type FormEventHandler<T = Element> = EventHandler<React.FormEvent<T>>

type ChangeEventHandler<T = Element> = EventHandler<React.ChangeEvent<T>>

type KeyboardEventHandler<T = Element> = EventHandler<React.KeyboardEvent<T>>

type MouseEventHandler<T = Element> = EventHandler<React.MouseEvent<T>>

type TouchEventHandler<T = Element> = EventHandler<React.TouchEvent<T>>

type PointerEventHandler<T = Element> = EventHandler<React.PointerEvent<T>>

type UIEventHandler<T = Element> = EventHandler<React.UIEvent<T>>

type WheelEventHandler<T = Element> = EventHandler<React.WheelEvent<T>>

type AnimationEventHandler<T = Element> = EventHandler<React.AnimationEvent<T>>

type TransitionEventHandler<T = Element> = EventHandler<

  React.TransitionEvent<T>

>

bivarianceHackОпределения типов для функций обработчиков событий, которые получаютeventобъект, а его тип — полученная универсальная переменнаяEтип, возвращаемое значениеvoid

Что касается того, почему bivarianceHack используется вместо (event: E): void, это связано с совместимостью функций в опции strictfunctionTypes. (событие: E): void, если параметр имеет производный тип, его нельзя передать функции, параметр которой является базовым классом.



class Animal {

  private x: undefined

}

class Dog extends Animal {

  private d: undefined

}



type EventHandler<E extends Animal> = (event: E) => void

let z: EventHandler<Animal> = (o: Dog) => {} // fails under strictFunctionTyes



type BivariantEventHandler<E extends Animal> = {

  bivarianceHack(event: E): void

}['bivarianceHack']

let y: BivariantEventHandler<Animal> = (o: Dog) => {}

Тип обещания

Мы часто используем его при выполнении асинхронных операций.asyncфункция, когда функция вызываетсяreturnОдинPromiseобъект, вы можете использоватьthenМетод для добавления функции обратного вызова.Promise<T>является универсальным типом,TОбщие переменные используются для определенияthenТип параметра первой функции обратного вызова, полученной методом.



type IResponse<T> = {

  message: string

  result: T

  success: boolean

}



async function getResponse(): Promise<IResponse<number[]>> {

  return {

    message: '获取成功',

    result: [1, 2, 3],

    success: true,

  }

}



getResponse().then(response => {

  console.log(response.result)

})

Сначала объявитеIResponseОбщий интерфейс используется для определенияresponseтип, черезTобщая переменная для определенияresultтип. Затем объявите асинхронную функциюgetResponseи определите тип возвращаемого значения функции какPromise<IResponse<number[]>>. последний звонокgetResponseметод вернетpromiseтип, черезthenЗвоните, в это времяthenПараметр первой функции обратного вызова, полученной методомresponseимеет тип,{ message: string, result: number[], success: boolean}.

Компоненты общих параметров

Атрибут имени следующего компонента указывает формат передачи параметра.Если вы хотите не указывать его, но хотите вывести фактический тип, передав тип параметра, вам необходимо использовать дженерики.



const TestB = ({ name, name2 }: { name: string; name2?: string }) => {

  return (

    <div className="test-b">

      TestB--{name}

      {name2}

    </div>

  )

}

Если вам нужно передать тип параметра извне, просто ->



type Props<T> = {

  name: T

  name2?: T

}

const TestC: <T>(props: Props<T>) => React.ReactElement = ({ name, name2 }) => {

  return (

    <div className="test-b">

      TestB--{name}

      {name2}

    </div>

  )

}



const TestD = () => {

  return (

    <div>

      <TestC<string> name="123" />

    </div>

  )

}

Когда использовать дженерики

Когда ваша функция, интерфейс или класс:

  • Когда нужно воздействовать на множество типов, приведите пример 🌰

Когда нам нужна функция id, параметр функции может быть любым значением, возвращаемое значение вернуть параметр как есть, и она может принимать только один параметр, в эпоху js мы запросто кинем строку

const id = arg => arg

Поскольку он может принимать любое значение, то есть входные параметры и возвращаемое значение нашей функции должны быть любого типа.Если мы не используем дженерики, мы можем только определить их повторно.



type idBoolean = (arg: boolean) => boolean

type idNumber = (arg: number) => number

type idString = (arg: string) => string

// ...

При использовании дженериков нам нужно только



function id<T>(arg: T): T {

  return arg

}



// 或



const id1: <T>(arg: T) => T = arg => {

  return arg

}
  • Когда его нужно использовать во многих местах, например, в часто используемых универсальных инструментах.Partial.

Функция заключается в преобразовании свойств типаИзмененный вариант,Обратите внимание, что это мелкоPartial.

type Partial<T> = { [P in keyof T]?: T[P] }

Если требуется глубокий Partial, мы можем сделать это с помощью общей рекурсии.

type DeepPartial<T> = T extends Function

  ? T

  : T extends object

  ? { [P in keyof T]?: DeepPartial<T[P]> }

  : T



type PartialedWindow = DeepPartial<Window>

ByteDance понимает набор команды Chedi

Мы являемся линейкой продуктов ByteDance для Know Chedi. В настоящее время бизнес находится в стадии быстрого развития. Know Chedi официально родился в августе 2017 года и всего за три года стал вторым в автомобильной интернет-индустрии.

В настоящее время основными технологическими стеками интерфейсной команды являются React и Typescript, которые в основном отвечают за понимание приложения Chedi, станции M, станции ПК, понимания матрицы продукта апплета Chedi, коммерциализации крупного бизнеса и коммерческих данных. продукты. У нас есть большое количество технических практик в различных сценариях приложений, таких как клиентское, мультихостинговое, техническое создание веб-сайтов, промежуточные и серверные системы, полный стек и богатое взаимодействие.Мы стремимся к развитию бизнеса на основе технологий и изучить все возможности.

Присоединяйтесь к Chedi и создайте самую профессиональную и открытую команду разработчиков в автомобильной сфере!

Резюме в прямом эфире:dcar_fe@bytedance.com

заголовок почты: заявление + город + должность