The Wayback Machine - https://web.archive.org/web/20220503092400/https://github.com/microsoft/TypeScript/issues/34692
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance members of literal type like const array type (e.g. string literal types should have literal length property) #34692

Open
samchon opened this issue Oct 24, 2019 · 6 comments
Labels
Awaiting More Feedback Suggestion

Comments

@samchon
Copy link

@samchon samchon commented Oct 24, 2019

The const array type, its principle members are also be the constant. When define a const array [number, string, boolean], its length type be 3. Also, when access to special index, the type also points the exact const type.

function const_array(): void
{
    let elements: [number, string, false] = [3, "something", false];
    let length: 3 = elements.length;

    let first: number = elements[0];
    let second: string = elements[1];
    let third: false = elements[2];
}

However, the literal type is not like the const array. When define a literal type "something", its length be not 9 but number. Also, when access to a special index, the type is not a special literal type but a string type.

function literal(): void
{
    let word: "something" = "something" as const;
    let length: number = something.length; // not 9 but number

    let first: string = word[0]; // not "s" but string
    let second: string = word[1]; // not "o" but string
    let third: string = word[2]; // not "m" but string
}

What about enhancing the literal type to be like the const array type?

@MartinJohns
Copy link

@MartinJohns MartinJohns commented Oct 24, 2019

Sounds like a duplicate of #34589.

@fatcerberus
Copy link

@fatcerberus fatcerberus commented Oct 24, 2019

No, I don't think so - #34589 is about tuple types. This is about using literal types for the .length and elements of a string literal.

@RyanCavanaugh RyanCavanaugh added Awaiting More Feedback Suggestion labels Oct 30, 2019
@RyanCavanaugh
Copy link

@RyanCavanaugh RyanCavanaugh commented Oct 30, 2019

Would be nice to understand why this would be useful

@samchon
Copy link
Author

@samchon samchon commented Oct 31, 2019

https://github.com/samchon/tgrid/blob/467aa3b8b619aab36bb50257feaa8de208de5888/src/components/Driver.ts#L85-L91

type is_edge_underscored<P> = P extends string
    ? P[0] extends "_"
        ? true
        : P[typeof (P.length - 1)] extends "_"
            ? true
            : false
    : false;

@RyanCavanaugh To implement a type detecting the edge-underscored string, I've also published a new issue #34844, hoping (Literal.length - 1) also be the constant value. However, I can't sure that I've requested exact features for the edge-underscored string. If I'm forgetting something important, please inform me.

@augustobmoura
Copy link

@augustobmoura augustobmoura commented Feb 6, 2020

There is a lot of use cases

One use case is asserting that a method is only called for a single character, mimicking the char type from other languages:

type SingleChar = string & { length: 1 };
const charCodeOf = (char: SingleChar): number => char.charCodeAt(0);

charCodeOf('a'); // Should work
charCodeOf('asdhfkj') // Should fail
charCodeOf('') // Should also fail

Also prevent literal empty strings from being passed as arguments:

type EmptyString = string & { length: 0 };
type SingleChar = string & { length: 1 };

const lastChar = (str: Exclude<string, EmptyString>): SingleChar => str[str.length - 1]!;

lastChar('abc'); // Should work
lastChar(''); // Should fail

// We could also better narrow the return types

const typedLastChar = <S extends string>(
  str: S,
): S extends EmptyString ? undefined : SingleChar => str[str.length - 1];

const ch1: string = typedLastChar('qwe'); // should work
const ch2: string = typedLastChar(''); // should fail
const ch3: undefined = typedLastChar(''); // should work

I'm sure there's others cases to type against fixed length strings (fixed length hashs maybe? or identifications cards?)

In my opninion the proposal is a really good addition, it's amazing for typing DSLs and builders

@unional
Copy link

@unional unional commented Jan 22, 2021

Another use case: currently some type level arithmetics leverage the fact that array length produces number literal.
This creates a performance issue.
I am doing that in type-plus and during development I have to limit the digits to 3-4 so that the IDE is still performant.

With template literal type, if 'abc'['length'] gets the same treatment of [1,1,1]['length'], there might be a big performance gain there.

Another example of type level arithmetics: Implementing Arithmetic Within TypeScript’s Type System

But of course, the best solution is adding

type Add<A extends number, B extends number> = intrinsic
type Subtract<A extends number, B extends number> = intrinsic
type Increment<A extends number> = Add<A, 1>
type Decrement<A extends number> = Subtract<A, 1>

🍺

@RyanCavanaugh RyanCavanaugh changed the title Enhance members of literal type like const array type Enhance members of literal type like const array type (e.g. string literal types should have literal length property) Mar 8, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting More Feedback Suggestion
Projects
None yet
Development

No branches or pull requests

6 participants