Repository navigation
keyof ignores constraint #44985
Description
Activity
MartinJohns commented
on Jul 12, 2021 ContributorMore actionsHaving
keyof Tas an indexer type would require #26797.So, does that mean it is currently not possible to do?
btw. why isK extends string & keyof Eventsnot enough to make it an indexable type since it requires 'string' or 'number' and the generic K must be a string and also keyof Events?MartinJohns commented
on Jul 12, 2021 ContributorMore actionsThe type
string & keyof Eventsis the same askeyof Events. And a union of keys can not be an index signature. You can use a mapped type instead.Reacted by Andrii Dieiev and 流浪大法师- addedQuestionAn issue which isn't directly actionable in codeAn issue which isn't directly actionable in code
on Jul 12, 2021 RyanCavanaugh commented
on Jul 12, 2021 MemberMore actionsThis works without issue
type Listeners<Events, K extends keyof Events> = Record<K, Listener<Events[K]>>;
Thanks guys,
the error message wasnt clear to me, but know I understand that you cant use a union of types which you get from the keyof - e.g. type union = 'a' | 'b' | 'c' to index but instead use it in either Record which handles the union case or use mapped type like{[key in K]: ... }instead of{[key: K]:Lastly, do you know why there is the last error at the
.push(listener)line in.on()method ts playgroundArgument of type 'Listener<Events[Type]>' is not assignable to parameter of type 'Listener<Events[keyof Events]>'. Type 'Events[keyof Events]' is not assignable to type 'Events[Type]'. Type 'keyof Events' is not assignable to type 'Type'. 'keyof Events' is assignable to the constraint of type 'Type', but 'Type' could be instantiated with a different subtype of constraint 'string | number | symbol'. Type 'string | number | symbol' is not assignable to type 'Type'. 'string | number | symbol' is assignable to the constraint of type 'Type', but 'Type' could be instantiated with a different subtype of constraint 'string | number | symbol'. Type 'string' is not assignable to type 'Type'. 'string' is assignable to the constraint of type 'Type', but 'Type' could be instantiated with a different subtype of constraint 'string | number | symbol'.(2345)it seems to me that those types should be the same, no? One is
Events[keyof Events](so basically any values of the Events) and the second one is the concrete eventEvents[Type]where the type is defined as constraint ofkeyof Eventson<Type extends keyof Events>(type: Type, listener: Listener<Events[Type]>): Unsubscribe { if (!type) throw new Error('Cannot call <EventEmitter>.on without a type'); if (!listener) throw new Error('Cannot call <EventEmitter>.on without a listener'); this.#listeners[type] = this.#listeners[type] || []; this.#listeners[type].push(listener); return () => { this.off(type, listener); } }
Looks like I had a mistake in the mapped type, working version for anyone interested
ts playgroundThanks Martin Johns (@MartinJohns) and Ryan Cavanaugh (@RyanCavanaugh)
- locked as resolved and limited conversation to collaborators
on Oct 21, 2025
Bug Report
🔎 Search Terms
keyof, generic constraint
🕗 Version & Regression Information
⏯ Playground Link
Playground link with relevant code
💻 Code
🙁 Actual behavior
I am getting ts errors even though the types work as expected. See // usage section
🙂 Expected behavior
The keyof returns the same type as the constraint generic and thus will be valid as index signature.