Можно ли разыграть undefined в void в TS? - PullRequest
3 голосов
/ 16 марта 2020

TLDR;

Это нормально? Или это плохая практика?

function isUndefined (payload: any): payload is undefined | void {
  return payload === undefined
}

Контекст

В TypeScript у меня есть функция, которая может возвращать либо что-то, либо undefined или void.

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

function eventHandler <T extends {[key: string]: any}> (payload: T): Modified<T> | undefined | void {
  // ... implementation
}

Тогда у меня есть средство проверки типа, которое должно проверить, он возвращает что-то отличное от void или undefined:

const result = eventHandler(payload)

if (result !== undefined) {
  // we have a modified payload!
}

Однако в приведенном выше фрагменте я получаю сообщение об ошибке, поскольку он говорит, что, хотя result !== undefined он все еще может быть void?

На мой взгляд, я думаю, что это странно, потому что void должно быть таким же, как undefined.

Так что я сделал этот тип проверки, который решает это:

function isUndefined (payload: any): payload is undefined | void {
  return payload === undefined
}

Это решает мой проблема, но мой вопрос:

Это нормально? Или это плохая практика?

Ответы [ 2 ]

1 голос
/ 16 марта 2020

Я думаю, вы делаете это более сложным, чем должно быть. Функция, которая возвращает void, может:

  1. Не иметь оператора возврата
  2. Есть оператор return; без указания значения.
  3. Есть return undefined; оператор.

В чистом javascript все вышеперечисленное будет иметь возвращаемое значение undefined. Если вы говорите, что функция возвращает undefined, то вы можете использовать только # 2 и # 3 из приведенного выше списка.

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

function foo(): string | void {
    return Math.random() > 0.5 ? 'abc' : 123
}

const val = foo()
if (val === undefined) {
    console.log('is undefined', val)
} else {
    console.log('is some value', val)
}

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

type PayloadModifier<T extends {[key: string]: any}> = (payload: T) => T | void

const setMaxAsTen: PayloadModifier<{a: number}> = (payload) => {
    if (payload.a > 10) {
        return { a: 10 }
    }
    return undefined // required unless noImplicitReturns is false
}

const val = setMaxAsTen({a: 5})
if (val === undefined) {
    console.log('is undefined', val)
} else {
    console.log('is some value', val)
}

Playground

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

1 голос
/ 16 марта 2020

void не undefined. void означает отсутствие возвращаемого значения. undefined - это тип значения, неопределенного во время выполнения.

это правда, что функция, которая не возвращает значения во время выполнения, возвращает undefined, но в системе типов TS мы решили сделать отсутствие возвращаемое значение специальное.

Например, присвоение (a) => void to (a) => number | undefined, вероятно, является ошибкой, хотя это безопасно во время выполнения.

В общем случае не используйте void, кроме как в возвращаемых типах функций. для всего остального используйте undefined.

Итак, да, нам нужно будет использовать разные проверки для undefined и void.

...