Указание типа возвращаемого значения функции с применением определенных ограничений

Я новичок в TypeScript и пытаюсь чего-то достичь или даже знать, возможно ли это.

Я хочу иметь возможность определять тип функции, которая позволяет экземплярам функции устанавливать свой собственный тип возвращаемого значения, но в то же время ограничивает этот тип возвращаемого значения как объект, где ключи являются строками, а значения - строками.

Таким образом, определение универсального типа должно разрешать любой возвращаемый тип, соответствующий { [key: string]: string }, но конкретный экземпляр функции может указывать, что он будет возвращать {a: 'y', b: 'z'}, а затем при использовании возвращаемого значения функции компилятор будет знать, что у него будут только свойства a и b, а не только какие-либо строковые свойства.

type obj = {
  name: string,
  doAThing: (path: string) => { [key: string]: string }
}

const anObj: obj = {
  name: 'Alias Fakename',
  doAThing: path => ({ a: 'abc', b: 'xyz' })
}

const result = anObj.functionInstance('abcdef')

В приведенном выше примере doAThing в anObj - допустимая реализация genericFunction. Но при использовании result компилятор не знает, что он будет иметь только свойства a и b, и позволяет использовать любой строковый ключ, например. result.keyWhichDoesntExist не вызывает ошибку типа.

Есть ли способ при определении doAThing в anObj указать его тип возвращаемого значения, чтобы подсказка типа работала с result, обеспечивая при этом соответствие указанного типа возвращаемого значения типу возврата genericFunction?


person Michael    schedule 24.07.2020    source источник


Ответы (1)


Вы хотите сделать свой тип функции универсальным с синтаксисом <T>:

type GenericFunction<T extends { [key: string]: string }> = (path: string) => T

Этот тип функции принимает другой тип T, который должен иметь имена строковых ключей и строковые значения, и каким бы ни был этот тип, именно это функция возвращает.

Затем вы можете использовать этот тип и заблокировать тот тип, с которым он работает, например:

const functionInstance: GenericFunction<{ a: string, b: string }> =
  (path: string) => ({ a: 'abc', b: 'xyz' })

Теперь, когда вы используете эту функцию, машинописный текст знает, что тип возвращаемого значения - { a: string, b: string }.

const result = functionInstance('a/path/here')
console.log(result.a) // 'abc'
console.log(result.b) // 'xyz'

площадка ссылка

Дополнительные сведения о универсальных шаблонах можно найти в руководстве.


Итак, эта функция является частью интерфейса?

Затем вы можете сделать сам интерфейс универсальным и сделать то же самое:

type MyObj<T extends { [key: string]: string }> = {
  name: string,
  doAThing: (path: string) => T
}

Теперь MyObj принимает общий параметр T, а doAThing() просто использует его.

Вы бы создали MyObj вот так:

const anObj: MyObj<{ a: string, b: string }> = {
  name: 'Alias Fakename',

  // doAThing() return type here is checked to match T
  doAThing: path => ({ a: 'abc', b: 'xyz' }) 
}

И теперь возвращаемое значение строго типизировано:

const result = anObj.doAThing('abcdef')
console.log(result.a) // works
console.log(result.b) // works

площадка

person Alex Wayne    schedule 24.07.2020
comment
Спасибо! Кажется, это хорошо работает. Но я понял, что недостаточно ясно сформулировал свой вопрос. Тип универсальной функции на самом деле является типом свойства объекта, и я не могу заставить его работать в этом случае. Я обновил свой вопрос, чтобы попытаться уточнить, что я имею в виду. - person Michael; 24.07.2020