microsoft / microsoft/TypeScript
Interface that extends another no longer constrains types like the original
未关闭
还没有人认领这个 Issue。
Bug
Domain: check: Type Inference
Help Wanted
- 主要语言
- Go
- 星标
- 111k
- 派生
- 14.3k
- 平均合并
- 1 天 19 小时
- 30 天内合并 PR
- 117
描述
🔎 Search Terms
interface
interface constrain
extend interface
🕗 Version & Regression Information
- This is the behavior in every version I tried, and I reviewed the FAQ for entries about interfaces.
⏯ Playground Link
💻 Code
/** SETUP ========================== */
function type<T>(): T { return null as unknown as T; }
type EventMap = Record<string, Event>;
type Listener<TEvent extends Event> = ((evt: TEvent) => void) | { handleEvent(object: TEvent): void };
export interface TypedEventEmitter<TEventMap extends EventMap> {
addEventListener<TEventType extends keyof TEventMap>(
type: TEventType,
listener: Listener<TEventMap[TEventType]>,
options?: AddEventListenerOptions | boolean,
): void;
removeEventListener<TEventType extends keyof TEventMap>(
type: TEventType,
listener: Listener<TEventMap[TEventType]>,
options?: EventListenerOptions | boolean,
): void;
}
/** END SETUP ========================== */
/**
* ✅ Sanity test
*/
type<TypedEventEmitter<{ foo: Event }>>() satisfies TypedEventEmitter<{ foo: Event }>; // ✅
// @ts-expect-error
type<TypedEventEmitter<{ bar: Event }>>() satisfies TypedEventEmitter<{ foo: Event }>; // ✅
/**
* ✅ Alias of the original type
*/
type CoolEventEmitter<TEventMap extends EventMap> = TypedEventEmitter<TEventMap>;
type<CoolEventEmitter<{ foo: Event }>>() satisfies TypedEventEmitter<{ foo: Event }>; // ✅
// @ts-expect-error
type<CoolEventEmitter<{ bar: Event }>>() satisfies TypedEventEmitter<{ foo: Event }>; // ✅
/**
* ❌ Interface that simply extends the original type
*/
interface CoolInterfaceEventEmitter<TEventMap extends EventMap> extends TypedEventEmitter<TEventMap> { }
type<CoolInterfaceEventEmitter<{ foo: Event }>>() satisfies TypedEventEmitter<{ foo: Event }>; // ✅
// @ts-expect-error
type<CoolInterfaceEventEmitter<{ bar: Event }>>() satisfies TypedEventEmitter<{ foo: Event }>; // ❌
/**
* ❌ Interface that extends the original type and adds stuff
*/
interface CoolInterfacePlusDispatchEventEmitter<TEventMap extends EventMap> extends TypedEventEmitter<TEventMap> {
dispatchEvent<TEventType extends keyof TEventMap>(ev: TEventMap[TEventType]): void;
}
type<CoolInterfacePlusDispatchEventEmitter<{ foo: Event }>>() satisfies TypedEventEmitter<{ foo: Event }>; // ✅
// @ts-expect-error
type<CoolInterfacePlusDispatchEventEmitter<{ bar: Event }>>() satisfies TypedEventEmitter<{ foo: Event }>; // ❌
/**
* ✅ Copy pasting the code instead of extending the interface works
*/
interface CopyPastedEventEmitter<TEventMap extends EventMap> {
addEventListener<TEventType extends keyof TEventMap>(
type: TEventType,
listener: Listener<TEventMap[TEventType]>,
options?: AddEventListenerOptions | boolean,
): void;
removeEventListener<TEventType extends keyof TEventMap>(
type: TEventType,
listener: Listener<TEventMap[TEventType]>,
options?: EventListenerOptions | boolean,
): void;
dispatchEvent<TEventType extends keyof TEventMap>(ev: TEventMap[TEventType]): void;
}
type<CopyPastedEventEmitter<{ foo: Event }>>() satisfies TypedEventEmitter<{ foo: Event }>; // ✅
// @ts-expect-error
type<CopyPastedEventEmitter<{ bar: Event }>>() satisfies TypedEventEmitter<{ foo: Event }>; // ✅
🙁 Actual behavior
As soon as the original interface is extended – whether the extender adds properties, does not add properties, uses the type parameter, or doesn't use the type parameter – I seem to lose the ability to constrain types in the same way as the original interface can.
🙂 Expected behavior
I would expect an interface that extends another to constrain types in exactly the same way as the original.
Additional information about the issue
No response
贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
调研方向
使用链接的 TypeScript Playground 和 issue 中的代码重现该行为,比较原始 interface、type alias 和扩展 interface。跟踪泛型约束的类型检查路径并添加回归测试;当扩展 interface 保留原始约束,且现有的 @ts-expect-error 情况按预期运行时,即视为完成。
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- typescript
- 领域
- compilers
- Issue 类型
- 缺陷
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 活跃度
- 停滞
- 描述清晰度
- 基本清楚
- 新手友好度
- 38/100