microsoft / microsoft/TypeScript
[bug] A method return type of 'this' is incorrectly converted to 'any' in declaration output
Nessuno ha ancora preso questa issue.
- Lingua principale
- Go
- Stelle
- 111k
- Fork
- 14.3k
- Merge medio
- 1g 19h
- PR unite (30g)
- 117
Descrizione
TypeScript Version: ^3.3.0-dev.20181129
Code
import * as events from 'events'
// EventArgs is used to create the event payload arguments for methods like
// EventEmitter.emit. This makes it possible to require a payload argument if
// the type is not `undefined`, or to not require an event payload argument if
// the type is `undefined`.
type EventArgs<
EventTypes,
K extends keyof EventTypes
> = EventTypes[K] extends undefined ? [] : [EventTypes[K]]
// our own version of EventEmitter with type-safe events (because the
// @types/node definition makes all events type `any`).
export interface IEventEmitter<EventTypes> {
new (): IEventEmitter<EventTypes>
addListener<EventName extends keyof EventTypes>(
event: EventName,
listener: (...args: EventArgs<EventTypes, EventName>) => void,
): this
on<EventName extends keyof EventTypes>(
event: EventName,
listener: (...args: EventArgs<EventTypes, EventName>) => void,
): this
once<EventName extends keyof EventTypes>(
event: EventName,
listener: (...args: EventArgs<EventTypes, EventName>) => void,
): this
removeListener<EventName extends keyof EventTypes>(
event: EventName,
listener: (...args: EventArgs<EventTypes, EventName>) => void,
): this
removeAllListeners<EventName extends keyof EventTypes>(
event?: EventName,
): this
emit<EventName extends keyof EventTypes>(
event: EventName,
...args: EventArgs<EventTypes, EventName>
): boolean
eventNames<EventName extends keyof EventTypes>(): Array<EventName>
setMaxListeners(n: number): this
getMaxListeners(): number
listeners<EventName extends keyof EventTypes>(
event: EventName,
): (...args: EventArgs<EventTypes, EventName>) => void[]
listenerCount<EventName extends keyof EventTypes>(type: EventName): number
prependListener<EventName extends keyof EventTypes>(
event: EventName,
listener: (...args: EventArgs<EventTypes, EventName>) => void,
): this
prependOnceListener<EventName extends keyof EventTypes>(
event: EventName,
listener: (...args: EventArgs<EventTypes, EventName>) => void,
): this
}
// This creates an EventEmitter class that uses our type definition. The
// implementation still comes from Node's EventEmitter.
//
// eslint-disable-next-line typescript/explicit-function-return-type
export function makeEventEmitterClass<EventTypes>() {
// merge the IEventEmitter interface and EventEmitter as IEventEmitter
// implementation into one.
// XXX Is there a better way?
const EventEmitter = class
extends ((events.EventEmitter as unknown) as IEventEmitter<EventTypes>) {}
// implements IEventEmitter<EventTypes> {}
return EventEmitter
}
Expected behavior:
Declaration file should not use any for method return types that return this.
I expect output like the following:
declare type EventArgs<EventTypes, K extends keyof EventTypes> = EventTypes[K] extends undefined ? [] : [EventTypes[K]];
export interface IEventEmitter<EventTypes> {
new (): IEventEmitter<EventTypes>;
addListener<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): IEventEmitter<EventTypes>;
on<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): IEventEmitter<EventTypes>;
once<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): IEventEmitter<EventTypes>;
removeListener<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): IEventEmitter<EventTypes>;
removeAllListeners<EventName extends keyof EventTypes>(event?: EventName): IEventEmitter<EventTypes>;
emit<EventName extends keyof EventTypes>(event: EventName, ...args: EventArgs<EventTypes, EventName>): boolean;
eventNames<EventName extends keyof EventTypes>(): Array<EventName>;
setMaxListeners(n: number): IEventEmitter<EventTypes>;
getMaxListeners(): number;
listeners<EventName extends keyof EventTypes>(event: EventName): (...args: EventArgs<EventTypes, EventName>) => void[];
listenerCount<EventName extends keyof EventTypes>(type: EventName): number;
prependListener<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): IEventEmitter<EventTypes>;
prependOnceListener<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): IEventEmitter<EventTypes>;
}
export declare function makeEventEmitterClass<EventTypes>(): {
new (): {
new (): IEventEmitter<EventTypes>;
addListener<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): IEventEmitter<EventTypes>;
on<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): IEventEmitter<EventTypes>;
once<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): IEventEmitter<EventTypes>;
removeListener<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): IEventEmitter<EventTypes>;
removeAllListeners<EventName extends keyof EventTypes>(event?: EventName | undefined): IEventEmitter<EventTypes>;
emit<EventName extends keyof EventTypes>(event: EventName, ...args: EventArgs<EventTypes, EventName>): boolean;
eventNames<EventName extends keyof EventTypes>(): EventName[];
setMaxListeners(n: number): IEventEmitter<EventTypes>;
getMaxListeners(): number;
listeners<EventName extends keyof EventTypes>(event: EventName): (...args: EventArgs<EventTypes, EventName>) => void[];
listenerCount<EventName extends keyof EventTypes>(type: EventName): number;
prependListener<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): IEventEmitter<EventTypes>;
prependOnceListener<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): IEventEmitter<EventTypes>;
};
addListener<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): IEventEmitter<EventTypes>;
on<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): IEventEmitter<EventTypes>;
once<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): IEventEmitter<EventTypes>;
removeListener<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): IEventEmitter<EventTypes>;
removeAllListeners<EventName extends keyof EventTypes>(event?: EventName | undefined): IEventEmitter<EventTypes>;
emit<EventName extends keyof EventTypes>(event: EventName, ...args: EventArgs<EventTypes, EventName>): boolean;
eventNames<EventName extends keyof EventTypes>(): EventName[];
setMaxListeners(n: number): IEventEmitter<EventTypes>;
getMaxListeners(): number;
listeners<EventName extends keyof EventTypes>(event: EventName): (...args: EventArgs<EventTypes, EventName>) => void[];
listenerCount<EventName extends keyof EventTypes>(type: EventName): number;
prependListener<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): IEventEmitter<EventTypes>;
prependOnceListener<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): IEventEmitter<EventTypes>;
};
export {};
//# sourceMappingURL=index.d.ts.map
Actual behavior:
Example of wrong output:
declare type EventArgs<EventTypes, K extends keyof EventTypes> = EventTypes[K] extends undefined ? [] : [EventTypes[K]];
export interface IEventEmitter<EventTypes> {
new (): IEventEmitter<EventTypes>;
addListener<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): this;
on<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): this;
once<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): this;
removeListener<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): this;
removeAllListeners<EventName extends keyof EventTypes>(event?: EventName): this;
emit<EventName extends keyof EventTypes>(event: EventName, ...args: EventArgs<EventTypes, EventName>): boolean;
eventNames<EventName extends keyof EventTypes>(): Array<EventName>;
setMaxListeners(n: number): this;
getMaxListeners(): number;
listeners<EventName extends keyof EventTypes>(event: EventName): (...args: EventArgs<EventTypes, EventName>) => void[];
listenerCount<EventName extends keyof EventTypes>(type: EventName): number;
prependListener<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): this;
prependOnceListener<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): this;
}
export declare function makeEventEmitterClass<EventTypes>(): {
new (): {
new (): IEventEmitter<EventTypes>;
// RIGHT HERE, the next lines have 'any'
addListener<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): any;
on<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): any;
once<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): any;
removeListener<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): any;
removeAllListeners<EventName extends keyof EventTypes>(event?: EventName | undefined): any;
emit<EventName extends keyof EventTypes>(event: EventName, ...args: EventArgs<EventTypes, EventName>): boolean;
eventNames<EventName extends keyof EventTypes>(): EventName[];
setMaxListeners(n: number): any;
getMaxListeners(): number;
listeners<EventName extends keyof EventTypes>(event: EventName): (...args: EventArgs<EventTypes, EventName>) => void[];
listenerCount<EventName extends keyof EventTypes>(type: EventName): number;
prependListener<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): any;
prependOnceListener<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): any;
};
addListener<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): IEventEmitter<EventTypes>;
on<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): IEventEmitter<EventTypes>;
once<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): IEventEmitter<EventTypes>;
removeListener<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): IEventEmitter<EventTypes>;
removeAllListeners<EventName extends keyof EventTypes>(event?: EventName | undefined): IEventEmitter<EventTypes>;
emit<EventName extends keyof EventTypes>(event: EventName, ...args: EventArgs<EventTypes, EventName>): boolean;
eventNames<EventName extends keyof EventTypes>(): EventName[];
setMaxListeners(n: number): IEventEmitter<EventTypes>;
getMaxListeners(): number;
listeners<EventName extends keyof EventTypes>(event: EventName): (...args: EventArgs<EventTypes, EventName>) => void[];
listenerCount<EventName extends keyof EventTypes>(type: EventName): number;
prependListener<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): IEventEmitter<EventTypes>;
prependOnceListener<EventName extends keyof EventTypes>(event: EventName, listener: (...args: EventArgs<EventTypes, EventName>) => void): IEventEmitter<EventTypes>;
};
export {};
//# sourceMappingURL=index.d.ts.map
This caused chaining method calls in my app not to work.
Playground Link: N/A
Related Issues:
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Direzione di ricerca
Riproduci il problema con TypeScript 3.3.0-dev.20181129 usando l’esempio fornito di IEventEmitter e makeEventEmitterClass, quindi confronta l’output delle dichiarazioni generato. Traccia la generazione delle dichiarazioni per i tipi restituiti inferiti dei metodi; il lavoro è completato quando i metodi generati conservano il tipo restituito IEventEmitter invece di any, con una copertura di regressione per questo caso.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- typescript
- Ambito
- compilers
- Tipo di issue
- Bug
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Stato di attività
- Ferma
- Chiarezza
- Specificata chiaramente
- Idoneità per principianti
- 30/100