Repository navigation
keyof to produce a runtime array #13267
Description
Activity
Perhaps this could be generalized to turning a union of literal types (as
keyof Foois, being'prop1' | 'prop2') into an array containing each member of the union once (['prop1', 'prop2']). I have a number of places I would like to see that, particularly for testing (have a test iterate over the array to make sure that each value supposedly acceptable to the union does, in fact, produce an appropriate result).in what order should these properties go?
I for one don't care; alphabetical, as-declared, officially-undefined, I just want it to be complete.
Reacted by Jacob Smithi think it should be a codefix (refactoring) rather than a runtime facility:
// before const x = keyof Foo; ^^^^^^^^^// codefix ______________________________________________ const x = keyof Foo; | | ^^^^^^^^^ < Replace with all names of `Foo` properties | |______________________________________________|// after const x = ["prop1", "prop2"];It's better than nothing but it definitely doesn't do everything I would have liked. For example, in my testing example, the entire point is ensuring complete coverage of the union for the test case. If a new item is added to the union, that array is still a valid array of items from that union, but it is no longer "complete"—some values from the union are not represented in the array.
on the other hand, the fact that there is no way to know the order of names in which they will be listed is disturbing
in a meanwhile there is a hack:
const mySample : Foo { prop1: 0, prop2: '' }; function toKeysBySample<T>(value: T): (keyof T)[] { return Object.keys(value); } const fooPropNames = toKeysBySample(mySample);although it's not perfect either: #12253 (comment)
That hack does nothing for the case of a union that isn't derived from
keyofthough. Personally, I am only concerned about order in a minority of cases; lacking knowledge of the order in this case wouldn't bother me. The type of the resulting "array" could also be a tuple, which would capture the order.Should permit generic parameters as the type.
that wouldn't that easy
function keys<T>(): (keyof T)[] { return keyof T; } console.log(keys<{ a: number; }>()); console.log(keys<{ c: bool; }>());
what would it emit? Consider:
- no object of type
Tto pass toObject.keys Tis generic, cannot emit static value atkeyof T- would need to introduce ambient parameter
- pass it only if it is used?
- need to resolve on call-site?
- generics can be propagated through call stack
- generics can be constructed from other generics (
T & G[]) .d.ts!
Reacted by Aluan Haddad and Herrington Darkholme- no object of type
a better hack that is almost to the point (yet has problems with unions)
interface Foo { kind: 'a'; value: number; } interface Baz { kind: 'b'; text: string; } type Bar = Foo | Baz; type Names<T> = { [P in keyof T]: P; } function toKeysBySample<T>(names: Names<T>): (keyof T)[] { return Object.values(names); } toKeysBySample<Bar>({ kind: 'kind', text: 'text' });
Igor Oleinikov (@Igorbek) has a good point, if we remember that any type driven emit is taboo
Reacted by Aluan Haddad and Herrington DarkholmeAs noted by Igor Oleinikov (@Igorbek) and Aleksey-Bykov, type directed emit is something that violate the TS goals of a fully erasable type system.
Moreover, a
keyof Tis not guaranteed to be the complete list at runt time you would get fromObject.keyssince the TS types are not exact/final.For both reasons, this is out of scope for the TypeScript project at the time being.
Reacted by Mariusz Pawelski and Frederick FogertyReacted by xnnkmd- addedSuggestionAn idea for TypeScriptAn idea for TypeScriptOut of ScopeThis idea sits outside of the TypeScript language design constraintsThis idea sits outside of the TypeScript language design constraints
on Jan 3, 2017 The second reason is the entire reason I wanted this feature. I don't want the complete runtime list. I want strictly and only the ones listed in the interface.
As for the first, I guess I just don't see why that should be a goal at all.
Reacted by Kevin Ryan, Aleksey Levenstein, Alex Turek, Paul Li, S. Chris Colbert, Chris, Michel Boudreau, Cedric Cazin, Samuel Sonne, Robert R. and 4 moreReacted by Frederick Fogertysaschanaz commented
on Jan 6, 2017 ContributorMore actionsProbably a duplicate or at least a sub-issue of #1549.
This is possible with custom transformers introduced by #13940.
See https://github.com/kimamula/ts-transformer-keys.Reacted by xnnkmd and gerich-homegwicksted commented
on Sep 14, 2017 ContributorMore actionsWhat about generating an enum at compile-time?
type A = { x: number, y: string }; enum B = keyof A; // as A exists right now during compilation for (var enumMember in B) { console.log("enum member: ", enumMember); }
which would write:
0 1 x y
and would have the following JS code:
(function (B) { B[B["x"] = 0] = "x"; B[B["y"] = 1] = "y"; })(B = exports.B || (exports.B = {}));
As to what order... doesn't matter to me. I just want this to validate a JSON config file against a TypeScript Interface without requiring something like
ajvor portions oftscitself likets-transformer-keysReacted by NN- locked and limited conversation to collaborators
on Jun 19, 2018
Put simply, I'd like a variant of keyof which produces the keys at runtime. E.g.,
In this case
xshould be["prop1", "prop2"].I've seen a few cases where people have tried to use
keyofin somewhat-similar fashions, but they all wanted the actual keys present in the object at runtime. I however very explicitly want to ignore any properties present in any hypothetical runtime Foo objects that are not present in the interface.Should permit generic parameters as the type.