想创建Maybe< T>在访问对象的属性之前,将包含某个对象并执行null / undefined检查的类。 当然,应该输入结果(可能< null>或者可能< TRes>)。
以下是一个例子:
class Maybe < T > {
constructor(public value: T) {}
static of < P > (obj: P): Maybe < P > {
return new Maybe(obj);
}
map < TResult > (fn: (arg: T) => TResult): Maybe < TResult > {
return this.isNothing ? nothing : new Maybe(fn(this.value));
}
public get < P extends keyof T > (name: P): Maybe < T[P] > {
return this.isNothing ? nothing : Maybe.of(this.value[name]);
}
get isNothing(): boolean {
return this.value == null;
}
}
let nothing = new Maybe(null);
Everethisng在这里工作正常并打字。对于exaple:
class Test {
a = {
id: 1,
name: "test1"
};
f = (foo: string) => {
return new Test();
};
};
let t = new Test();
console.log(Maybe.of(t).get('a').get('name').value); // ok
但是定义“apply”函数有问题,它接受对象属性的名称,实际上是一个函数,执行该函数并返回Maybe&lt; TResult&gt;。
// T[fName]: (...args)=> TResult
public apply < P extends keyof T > (fnName: P, ...args: any[]) /*: Maybe<Tresult> */ {
if (!this.isNothing) {
let res = null;
let fn = this.value[fnName];
if (isF(fn)) {
return Maybe.of(fn(...args));
}
}
return nothing;
}
无法找到定义“应用”调用结果的解决方案。
let fResult = Maybe.of(t).apply('f', 'foo');
// fResult is Maybe<any> , expected to be Maybe<Test>
有人知道如何定义“申请”结果的类型吗?或者甚至可以在TS 2.3中实现这一点?
这里有相同代码的游乐场上的链接: TS playground
由于
答案 0 :(得分:0)
首先,让我把Maybe<T>
课放在一边,一步一步地介绍一些基本操作。
您可以使用泛型函数来检查对象是否为null,然后返回该对象的某些属性。函数的返回类型可以从属性的类型推断出来:
function maybeGet<T, N extends keyof T>(t: T | undefined, n: N) {
return t ? t[n] : undefined;
}
使用Test
班级
class Test {
a = {
id: 1,
name: "test1"
};
f = (foo: string) => {
return new Test();
};
};
let t = new Test();
你可以像这样使用它
const a = maybeGet(t, 'a');
确实a
的类型被推断为{ id: number; name: string; }
然后,您可以定义描述某些函数的泛型类别别名,返回类型为R
:
type FR<R> = (...args: any[]) => R;
然后定义将接受另一个函数的泛型函数,如果它不为null则调用它。函数的返回类型是从其参数的返回类型推断出来的:
function maybeApplyFunction<R>(f: FR<R> | undefined, ...args: any[]) {
return f ? f(...args) : undefined;
}
const r = maybeApplyFunction(t.f, 'foo'); // r has type 'Test'
你可以明确地将两者结合在一起,没有问题
const tf = maybeApplyFunction(maybeGet(t, 'f'), 'foo');
// tf has type `Test`
问题是将两者结合在一个通用操作中。
使用映射类型,您可以尝试为具有返回R
作为属性的函数的对象定义类型别名
type FM<N extends string, R> = {[n in N]: FR<R>};
并使用
编写泛型函数function maybeApplyMemberFunction<N extends string, R>(o: FM<N, R>, n: N, ...args: any[]) {
return o ? o[n](...args) : undefined;
}
它甚至适用于某些情况
class T1 { f() { return new T1() } };
const b = maybeApplyMemberFunction(new T1(), 'f');
// b has type T1
但是,它不适用于您的测试,因为TypeScript由于某种原因将使用keyof T
作为N
,并坚持Test
中的所有属性都必须是可调用的:
const tm = maybeApplyMemberFunction(t, 'f');
// Argument of type 'Test' is not assignable to parameter of type
// 'FM<"a" | "f", Test>'.
// Types of property 'a' are incompatible.
// Type '{ id: number; name: string; }' is not assignable to type 'FR<Test>'.
// Type '{ id: number; name: string; }' provides no match for the signature
// '(...args: any[]): Test'.
如果您将N
限制为精确的文字类型,则可以使用:
function maybeApplyMemberFunctionF<N extends 'f', R>(o: FM<N, R>, n: N, ...args: any[]) {
return o ? o[n](args) : undefined;
}
const t1 = maybeApplyMemberFunctionF(t, 'f');
不幸的是,typescript没有办法指定N
应该是n
参数的确切文字类型。