将函数作为参数传递时如何增加类型安全性?

jku*_*chi 5 typescript typescript-generics

我很好奇如何正确地输入关于泛型的函数参数。

看下面的基本示例,我有2个功能:- sayHellorunAnyFunction

现在,第一个调用sayHello显然是一个错误,传递给函数的数据没有name参数。完美和期望。

问题出在下一部分,那里有一个函数runAnyFunction,该函数将一个函数作为其第一个参数,obj作为其第二个参数,并简单地运行obj作为参数传递的函数。

下面的示例中的以下2个函数将通过打字稿检查没有问题,这就是我的问题。

runAnyFunction<Person>(sayHello, {
  name: "Bob"
});

runAnyFunction<Monster>(sayHello, {
  size: "HUGE"
});
Run Code Online (Sandbox Code Playgroud)

我知道第二个电话会给我一个Hello undefined,这是不希望的。理想情况下,我希望此调用使类型检查失败,因为这不应该被允许。

我的想法是这里的罪魁祸首是fn函数参数,因为它自己的obj参数将被推断为any,但是我很难为此编写正确的类型。

我知道在这个演示中,我runAnyFunction的函数实际上只是运行任何函数,但是如果有一种首选的方式来键入具有这种性质的函数,我很想知道。

如何正确输入?


代码样例

// demo.ts

type Fn = (obj) => string;

interface Person {
  name: string;
}

interface Monster {
  size: string;
}

const somePerson: Person = {
  name: "Bob"
};

const someMonster: Monster = {
  size: "HUGE"
};


sayHello(someMonster); // ERROR, 'name' is missing in type. Sure, expected.


// sayHello requires an obj of type Person
export function sayHello(obj: Person): string {
  return `Hello ${obj.name}`;
}

// Simple function that runs any function, passing obj to it
export function runAnyFunction<T>(fn: Fn, obj: T): void {
  const res = fn(obj);
  console.log(res);
}

// Person has name, this works
runAnyFunction<Person>(sayHello, {
  name: "Bob"
});

// I'm passing sayHello, which should require an object with a `name`
// but it does not error
runAnyFunction<Monster>(sayHello, {
  size: "HUGE"
});

Run Code Online (Sandbox Code Playgroud)

Sha*_*tin 3

您还需要使您的Fn类型变得通用:

type Fn<T> = (obj: T) => string;
export function runAnyFunction<T>(fn: Fn<T>, obj: T): void {
    const res = fn(obj);
    console.log(res);
}
Run Code Online (Sandbox Code Playgroud)

您之前没有收到错误的原因是您的Fn类型隐式具有any其第一个参数的类型:

type Fn = (obj) => string; // obj is implicitly of type any
Run Code Online (Sandbox Code Playgroud)