仅当映射到它的类型未定义时,如何才能使arg为可选?

时间:2018-12-01 07:40:54

标签: typescript optional-parameters mapped-types

例如,如果我们有以下代码,

type Events = {
    SOME_EVENT: number
    OTHER_EVENT: string
    ANOTHER_EVENT: undefined
}

interface EventEmitter<EventTypes> {
  on<K extends keyof EventTypes>(s: K, listener: (v: EventTypes[K]) => void);
}

declare const emitter: EventEmitter<Events>;

emitter.on('SOME_EVENT', (payload) => testNumber(payload));
emitter.on('OTHER_EVENT', (payload) => testString(payload));

function testNumber( value: number ) {}
function testString( value: string ) {}

playground link)有效,我们如何做到这一点,以便发出呼叫不需要ANOTHER_EVENT事件的第二个arg?

例如,我可以添加以下行,它可以正常工作:

emitter.emit('OTHER_EVENT', 'foo')

playground link

但是,如果我想用emit来调用'ANOTHER_EVENT',我想在没有第二个参数的情况下进行此操作:

emitter.emit('ANOTHER_EVENT') // ERROR, expected 2 arguments, but got 1.

给出错误,因为它需要第二个arg。 (playground link

要使其正常运行,我必须写:

emitter.emit('ANOTHER_EVENT', undefined)

playground link

仅在用emit调用'ANOTHER_EVENT'的情况下,如何才能使第二个arg不是必需的?

2 个答案:

答案 0 :(得分:1)

您可以在其余参数中使用元组,以根据第一个参数更改参数的数量(甚至是可选参数)。

type Events = {
    SOME_EVENT: number
    OTHER_EVENT: string
    ANOTHER_EVENT: undefined
}

type EventArgs<EventTypes, K extends keyof EventTypes> = EventTypes[K] extends undefined ?[]:[EventTypes[K]]
interface EventEmitter<EventTypes> {
    on<K extends keyof EventTypes>(s: K, listener: (...v: EventArgs<EventTypes,K>) => void);
    emit<K extends keyof EventTypes>(s: K, ...v: EventArgs<EventTypes,K>);
}

declare const emitter: EventEmitter<Events>;

emitter.on('SOME_EVENT', (payload) => testNumber(payload));
emitter.on('OTHER_EVENT', (payload) => testString(payload));

function testNumber(value: number) {}
function testString(value: string) {}

emitter.emit('OTHER_EVENT', 'foo')

emitter.emit('ANOTHER_EVENT')

答案 1 :(得分:0)

您可以使用?将第二个参数设为可选:

type Events = {
    SOME_EVENT: number
    OTHER_EVENT: string
    ANOTHER_EVENT?: undefined
}

interface EventEmitter<EventTypes> {
    on<K extends keyof EventTypes>(s: K, listener: (v: EventTypes[K]) => void);
    emit<K extends keyof EventTypes>(s: K, v?: EventTypes[K]);
}

declare const emitter: EventEmitter<Events>;

emitter.on('SOME_EVENT', (payload) => testNumber(payload));
emitter.on('OTHER_EVENT', (payload) => testString(payload));

function testNumber(value: number) {}
function testString(value: string) {}

emitter.emit('OTHER_EVENT', 'foo')

emitter.emit('ANOTHER_EVENT')

根据第一个参数的输入,我认为不可能将其设置为可选。在这种情况下,您只需要两种不同的方法即可。