Определение функции с использованием универсальных

#javascript #typescript

Вопрос:

Имея такой простой код:

 interface ServerData {
  foo: string
  bar: number
}

const oo = {
  foo: "abc",
  bar: 887
}

function foo<ServerData>(x: ServerData): number { return x.foo }
 

Я получаю ошибку в
последней строке:

 Property 'foo' does not exist on type 'ServerData'
 

Это странно, так ServerData как интерфейс уже определен выше. Что происходит?

Ответ №1:

Это связано с тем, что универсальный тип ServerData , определенный в функции, может не обладать свойством foo (универсальный и интерфейс-это не одно и то же, вы должны сообщить об этом компилятору).

Нигде в коде вы не говорите компилятору, что универсальный код обладает этим свойством. В вашем случае вы могли бы полностью избавиться от общего типа, как это (также вам пришлось бы преобразовать foo в число, так как функция возвращает число):

 function foo(x: ServerData): number { return Number(x.foo) }
 

или вы могли бы сообщить компилятору, что универсальный тип в функции реализует ServerData интерфейс следующим образом:

 function foo<T extends ServerData>(x: T): number { return Number(x.foo) }
 

Основная проблема здесь заключается в том, что вы не сообщаете компилятору, что на самом деле представляет собой этот тип, поэтому он не знает, что параметр обладает этим свойством. Если вы хотите передать универсальный код и сообщить компилятору, что свойство foo существует, вы также можете сделать это:

 function foo<T extends {foo: string}>(x: T): number { return Number(x.foo) }
 

Ответ №2:

Дополнение к ответу @WilsonPena.

В вашем объявлении foo функции ServerData указана переменная локального типа; она не относится к глобальному типу/интерфейсу ServerData . Ваша декларация фактически эквивалентна

 function foo<T>(x: T): number { return x.foo }
 

Здесь яснее, что неизвестно, есть ли у объекта x поле foo .

Чего вы, вероятно, хотите, так это

 function foo(x: ServerData): number { return x.foo }
 

Теперь движок типов знает, что поле foo включено x . Однако вы получите еще одну ошибку, так как поле foo в ServerData является строкой, но вы объявили, что функция foo возвращает число.