[英]Creating a function type where the return type depends on the existence of an optional parameter
考虑以下 JS function 和示例用法:
const fooInteractor = function(state, foo) {
if (foo) {
return {...state, foo}
} else {
return state.foo
}
}
const state = {foo: 'foo', other: 'data'};
fooInteractor(state); // returns 'foo'
fooInteractor(state, 'bar'); // return {foo: 'bar', other: 'data'}
// we pass this function around generically and use it to interact with state
function interacts(state, interactorFn) {
// ie interactorFn(state);
}
interacts(state, fooInteractor);
我怎样才能在 TS 土地上输入这个?
我可以定义一个类型并与 Typescript 满意的类型交互:
type StateInteractor {
(state: State): string
(state: State, value: string): State
}
function interact(state: State, stateFn: StateInteractor) {
const data: string = stateFn(state);
const changedState: State = stateFn(state, data);
// etc
}
但是,在实际实施StateInteractor
时,我遇到了问题:
const fooInteractor: StateInteractor = function(state: State, foo?: string) {
if (foo) {
return {...state, foo} as State
} else {
return state.foo as string
}
}
/*
Type '(state: State, foo?: string) => string | State' is not assignable to type 'StateInteractor'.
Type 'string | State' is not assignable to type 'string'.
Type 'State' is not assignable to type 'string'.ts(2322)
*/
我也无法使用箭头功能/lambda。
请注意,我可以通过 function 重载来做到这一点:
function fooInteractor(state: State): string
function fooInteractor(state: State, value: string): State
function fooInteractor(state: State, value?: string) {
if (value) {
return {...state, foo: value} as State
} else {
return state.foo as string
}
}
// This compiles and works as expected
const typedFooInteractor: StateInteractor = fooInteractor
interact(someState, typedFooInteractor)
但这非常丑陋和奇怪,并且每次我实现一个时都需要重新定义 StateInteractor 类型(通过重载)。
我们可以使用通用参数默认值和条件类型作为返回值,将重载逻辑压缩到通用 function 签名中。 游乐场版
V extends string | undefined = undefined
V extends string | undefined = undefined
(通用默认值)表示V
是字符串或未定义,默认情况下未定义。 条件返回V extends string? State: string
V extends string? State: string
使用三元语法根据V
的类型返回。
type State = Record<string, any>
// define a function type whose return value depends on an argument
type StateInteractor = <S extends State, V extends string | undefined = undefined>(state: S, value?: V) => V extends string ? State : string
// define an instance
const fooInteractor: StateInteractor = (state: State, foo?: string) => {
if (foo) {
return {...state, foo}
} else {
return state.foo
}
}
// test it
const state = {foo: 'foo', other: 'data'};
const shouldBeFoo = fooInteractor(state); // returns 'foo'
const shouldBeState = fooInteractor(state, 'bar'); // return {foo: 'bar', other: 'data'}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.