Skip to content

Suggestion: Object.getOwnPropertyNames and Object.keys should return type with keyof #15570

Closed
@SimonMeskens

Description

@SimonMeskens

The signature of Object.getOwnPropertyNames is getOwnPropertyNames(o: any): string[];

Would it be possible to get getOwnPropertyNames<T>(o: T): (keyof T)[]; instead?

The same for Object.keys: keys<T>(o: T): (keyof T)[];

If I'm correct, this doesn't cause any edge cases, but allows us to write more typesafe code. Right now, I'm forced to cast some things.

Here's a toy example:

const Suits = {
    clubs: { toString: () => '\u2663' },
    diamonds: { toString: () => '\u2666' },
    hearts: { toString: () => '\u2665' },
    spades: { toString: () => '\u2660' }
}

type Suit = keyof typeof Suits;

const Ranks = {
    ace: { valueOf: () => 1, toString: () => 'A' },
    deuce: { valueOf: () => 2, toString: () => '2' },
    three: { valueOf: () => 3, toString: () => '3' },
    four: { valueOf: () => 4, toString: () => '4' },
    five: { valueOf: () => 5, toString: () => '5' },
    six: { valueOf: () => 6, toString: () => '6' },
    seven: { valueOf: () => 7, toString: () => '7' },
    eight: { valueOf: () => 8, toString: () => '8' },
    nine: { valueOf: () => 9, toString: () => '9' },
    ten: { valueOf: () => 10, toString: () => 'T' },
    jack: { valueOf: () => 11, toString: () => 'J' },
    queen: { valueOf: () => 12, toString: () => 'Q' },
    king: { valueOf: () => 13, toString: () => 'K' }
}

type Rank = keyof typeof Ranks;

type Card<R extends Rank, S extends Suit> = { rank: R, suit: S }

let deck = Object
    .keys(Suits)
    .reduce<Card<Rank, Suit>[]>((cards, suit) =>
        cards.concat(Object
            .keys(Ranks)
            .map(rank => ({
                rank: <Rank>rank, // Should be inferred instead
                suit: <Suit>suit  // Should be inferred instead
            }))
        ),
    []);

As you can see, at the end there I'm forced to cast rank and suit, they should be inferred. If I change lib.d.ts to have the signature I suggest, it correctly infers the types there. It shouldn't cause edge cases or break code as I can't imagine there's any code that expects Object.keys to return a string that's not a key of that object.

The above code is MIT license btw, if anyone feels like using it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions