[英]TypeScript: Is it possible to restrict arrow function parameter return type?
I have a typescript function that accepts two params, a config object
and a function
:我有一个 typescript 函数,它接受两个参数,一个配置
object
和一个function
:
function executeMaybe<Input, Output> (
config: { percent: number },
fn: (i: Input) => Output
): (i: Input) => Output | 'maybe next time 😛' {
return function(input: Input) {
return Math.random() < config.percent / 100
? fn(input)
: 'maybe next time 😛';
};
}
Usage of the function looks like this:该函数的用法如下所示:
interface Foo { number: number; }
interface Bar { string: string; }
const makeBarMaybe = executeMaybe<Foo, Bar>(
{ percent: 75 },
foo => ({ string: `derived from Foo: ${JSON.stringify(foo)}` })
);
If I attempt to add a nonexistent property to my config object literal, TypeScript kindly informs me:如果我尝试向我的配置对象文字添加一个不存在的属性,TypeScript 会通知我:
Argument of type '{ percent: number;
'{百分比:数字; baz: string;
baz:字符串; }' is not assignable to parameter of type '{ percent: number;
}' 不能分配给类型为 '{ percent: number; 的参数; }'.
}'。 Object literal may only specify known properties, and 'baz' does not exist in type '{ percent: number;
对象字面量只能指定已知的属性,而 'baz' 不存在于类型 '{ percent: number; }'.
}'。 (2345)
(2345)
However, when I add an additional property to the object returned from the function param, no error is mentioned:但是,当我向从函数参数返回的对象添加附加属性时,没有提到错误:
Is it possible to have TS provide an error in this scenario without explicitly providing the function's return type?在这种情况下是否可以让 TS 提供错误而不显式提供函数的返回类型?
Here's a StackBlitz where I was playing around with this.这是我在玩这个的StackBlitz 。
You see this error because of excess-property-checks .您看到此错误是因为extra-property-checks 。 Literal objects are treated in a differen way.
文字对象的处理方式不同。
Object literals get special treatment and undergo excess property checking when assigning them to other variables, or passing them as arguments.
对象文字在将它们分配给其他变量或将它们作为参数传递时会得到特殊处理并进行额外的属性检查。 If an object literal has any properties that the “target type” doesn't have, you'll get an error:
如果对象字面量具有“目标类型”没有的任何属性,您将收到错误消息:
If you still want to add more extra properties to your argument, you should expect a subtype of Foo
instead of super type.如果你仍然想为你的参数添加更多额外的属性,你应该期待
Foo
的子类型而不是超类型。 I mean, that your argument should extend
Foo
instead of being Foo
.我的意思是,你的论点应该
extend
Foo
而不是Foo
。
You need to rewrite your executeMaybe
and apply a constraint where callback
function expects subtype of Input
instead of Input
itself:您需要重写您的
executeMaybe
并应用一个约束,其中callback
函数需要Input
子类型而不是Input
本身:
function executeMaybe<Input, Output>(
config: { percent: number },
fn: <Inp extends Input>(i: Inp) => Output
): <Inp extends Input>(i: Inp) => Output | 'maybe next time 😛' {
return function (input: Input) {
const result =
Math.random() < config.percent / 100 ? fn(input) : 'maybe next time 😛';
console.log(result);
return result;
};
}
WHole code:全码:
function executeMaybe<Input, Output>(
config: { percent: number },
fn: <Inp extends Input>(i: Inp) => Output
): <Inp extends Input>(i: Inp) => Output | 'maybe next time 😛' {
return function (input: Input) {
const result =
Math.random() < config.percent / 100 ? fn(input) : 'maybe next time 😛';
console.log(result);
return result;
};
}
console.clear();
interface Foo {
number: number;
}
interface Bar {
string: string;
}
const makeBarMaybe = executeMaybe<Foo, Bar>({ percent: 75 }, (foo) => ({
string: `derived from Foo: ${JSON.stringify(foo)}`,
}));
const explicitFoo: Foo = { number: 10 };
const implicitFoo = { number: 20 };
const superFoo = { number: 30, extra: 'super' };
makeBarMaybe(explicitFoo);
makeBarMaybe(implicitFoo);
makeBarMaybe(superFoo); // same object | duck typing allows
makeBarMaybe({ number: 30, extra: 'super' }); // ok
UPDATE更新
My bad, probably did not understand the question.我的不好,可能没看懂问题。
TypeScript does not support exact types, but there is a workaround: TypeScript 不支持精确类型,但有一个解决方法:
type PseudoExact<T, U> = T extends U ? U extends T ? U : never : never
function executeMaybe<Input, Output>(
config: { percent: number },
fn: <Inp extends Input>(i: PseudoExact<Input, Inp>) => Output
): <Inp extends Input>(i: PseudoExact<Input, Inp>) => Output | 'maybe next time 😛' {
return function <Inp extends Input>(input: PseudoExact<Input, Inp>) {
const result =
Math.random() < config.percent / 100 ? fn(input) : 'maybe next time 😛';
console.log(result);
return result;
};
}
PseudoExact
- checks whether supertype extends subtype. PseudoExact
- 检查超类型是否扩展了子类型。
WHole code with expected errors:具有预期错误的完整代码:
type PseudoExact<T, U> = T extends U ? U extends T ? U : never : never
function executeMaybe<Input, Output>(
config: { percent: number },
fn: <Inp extends Input>(i: PseudoExact<Input, Inp>) => Output
): <Inp extends Input>(i: PseudoExact<Input, Inp>) => Output | 'maybe next time 😛' {
return function <Inp extends Input>(input: PseudoExact<Input, Inp>) {
const result =
Math.random() < config.percent / 100 ? fn(input) : 'maybe next time 😛';
console.log(result);
return result;
};
}
console.clear();
interface Foo {
number: number;
}
interface Bar {
string: string;
}
const makeBarMaybe = executeMaybe<Foo, Bar>({ percent: 75 }, (foo) => ({
string: `derived from Foo: ${JSON.stringify(foo)}`,
}));
const explicitFoo: Foo = { number: 10 };
const implicitFoo = { number: 20 };
const superFoo = { number: 30, extra: 'super' };
makeBarMaybe(explicitFoo);
makeBarMaybe(implicitFoo);
makeBarMaybe(superFoo); // expected error
makeBarMaybe({ number: 30, extra: 'super' }); // expected error
Instead of my naive PseudoExact
you can use more advanced type utility.您可以使用更高级的类型实用程序,而不是我天真的
PseudoExact
。 Please see this comment请看这条评论
export type Equals<X, Y> =
(<T>() => T extends X ? 1 : 2) extends
(<T>() => T extends Y ? 1 : 2) ? true : false;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.