繁体   English   中英

TypeScript 具有推断返回类型的通用 function

[英]TypeScript generic function with inferred return type

如何键入具有通用参数的 function,然后可以返回任何类型,并从用法中推断出 function 的返回类型?

我试过这个:

type Thing<T> = <U>(value: T) => U

const shouldMakeStrings: Thing<string> = (a: string) => a + 'foo'
const shouldMakeObjects: Thing<string> = (a: string) => ({ foo: a })

我的期望是shouldMakeStrings的类型是(a: string) => stringshouldMakeObjects的类型是(a: string) => { foo: string }

相反,它们会出错,因为'U' could be instantiated with an arbitrary type which could be unrelated to 'string'

如何在不定义 U 的情况下定义Thing类型,同时告诉它我想要允许任何返回类型?


这是我正在尝试做的更完整的示例( 游乐场链接):

type Thing<T> = <U>(value: T) => U

// Example, this will be a big map of custom types and string representations
type Types = {
  'string': string,
  'number': number
}

type CallbackMap = {
  [P in keyof Types]?: Thing<Types[P]>
}

const callbacks: CallbackMap = {}

const addCallback = <V>(type: keyof Types, callback: Thing<V>) => {
  callbacks[type] = callback
}

addCallback('string', (a: string) => a + 'foo')
addCallback('number', (a: number) => { foo: a })

callbacks.string // = callback that takes a string and returns something, with it's type inferred as string from `addCallback('string')` above
callbacks.number // = callback that takes a number and returns something, with it's type inferred as '{ foo: number }' from `addCallback('number')` above

这是一个更详细的示例,但它还有其他 TypeScript 问题( 操场):

type A = { foo: string }
type B = { bar: string }
type C = number[]

type Modifiable = {
  'typeA': A,
  'typeB': B,
  'typeC': C
}

type Modifier<T> = <U>(value: T) => U
type ModifierMap = {
  [P in keyof Modifiable]?: Modifier<Modifiable[P]>
}

const modifiers: ModifierMap = {
  'typeA': (a: A) => a
}

const setModifier = <V extends keyof Modifiable = keyof Modifiable>(type: V, callback: Modifier<Modifiable[V]>) => {
  modifiers[type] = callback
}

setModifier('typeA', (input: A) => input.foo + 'a')

setModifier('typeA', a => a.foo)

// With the aim to be able to do something like this:
const makeModifiedA = (modifiers?: ModifierMap) => {
  const a = { foo: "hello world" }

  return modifiers?.typeA ? modifiers.typeA(a) : a
}

makeModifiedA(modifiers) // = "hello world"
setModifier('typeA', (input: A) => ({ ...input, upperFoo: input.foo.toUpperCase() }))
makeModifiedA(modifiers) // = { foo: "hello world", upperFoo: "HELLO WORLD" }

any / unknown都会匹配吗?

type Thing<T> = (value: T) => unknown

const shouldMakeStrings: Thing<string> = (a: string) => a + 'foo'
const shouldMakeObjects: Thing<string> = (a: string) => ({ foo: a })

操场

在 TypeScript 中,您可以分配类型或推断类型。 你不能两者兼得。

您可以做的一件事是编写 hack 来检查 function 是否“满足”约束而不“擦除”其类型。 然后仍会推断其类型,但首先会对其进行约束检查。

const satisfies = <Constraint>() => <Input extends Constraint>(input: Input) => input;

const checked = satisfies<(arg: string) => any>()(arg1 => {
  console.log(arg1);
  return 2;
});

实际上有一个相关的提案正在进行中,很快就会将其添加为语言功能, satisfies运算符。

https://github.com/microsoft/TypeScript/issues/47920

所以在未来的 TS 4.9+ 你会写这样的东西:

const checked = ((arg1: string) => 2) satisfies (arg: string) => any

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM