Как добавить безопасность типов при передаче функций в качестве аргументов?

#typescript #typescript-generics

#typescript #typescript-generics

Вопрос:

Мне любопытно, как правильно вводить параметры функции, касающиеся обобщений.

Глядя на следующий базовый пример, у меня есть 2 функции: — sayHello amp; runAnyFunction

Итак, первый вызов sayHello явно является ошибкой, данные, переданные функции, не имеют name параметра. Идеально и ожидаемо.

Проблема в следующей части, где у нас есть функция, runAnyFunction которая принимает функцию в качестве своего первого параметра, obj в качестве своего второго параметра и просто запускает функцию, передаваемую obj в качестве аргумента.

Следующие 2 функции в приведенном ниже примере без проблем пройдут проверки typescript, и это моя проблема.

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

runAnyFunction<Monster>(sayHello, {
  size: "HUGE"
});
  

Я знаю, что второй вызов выдаст мне Hello undefined , что нежелательно. В идеале я бы хотел, чтобы этот вызов не выполнял проверку типа, поскольку это не должно быть разрешено.

Я думаю, что виновником здесь является fn параметр функции, поскольку его собственный obj параметр будет выведен как any , но у меня возникают трудности с написанием правильного набора текста для этого.

Я понимаю, что в этой демонстрации my 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"
});

  

Ответ №1:

Вам также нужно сделать свой Fn тип универсальным:

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

Причина, по которой вы не получали ошибку раньше, заключается в том, что ваш Fn тип implicity имел any тип для своего первого параметра:

 type Fn = (obj) => string; // obj is implicitly of type any
  

Комментарии:

1. идеально, имеет полный смысл. Спасибо!

2. Всегда пожалуйста. Я рад, что вы смогли понять такое короткое объяснение.