microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
100.9k stars 12.47k forks source link

Template literal types not giving autocomplete suggestions #41620

Open armondwillingham opened 3 years ago

armondwillingham commented 3 years ago

TypeScript Version: 4.1.2

Search Terms: Template literal type autocomplete suggestion lint Code

        type autocomplete = `meeting`;
        type noAutocomplete = `meeting/${number}`;
        const val: noAutocomplete = 'meet';

Expected behavior: Beginning to fill out a string on a template literal type will give a useful autocomplete suggestion, like filling it out with a string literal type. Actual behavior: In VSCode, there is no autocomplete suggestion and in the TypeScript Playground the suggestion is incorrect.

Playground Link: https://www.typescriptlang.org/play?ts=4.2.0-dev.20201120#code/C4TwDgpgBAhgrsA9gY0QWzAGwsaBeKAAzQhwEsA7Ac0IG4AoUSKCxAQQRXSx3yJOCUqAegAkAbwpw0AIwgAnAL516qCgGdgUAG4xMALlidUGbLigEA5CXLVLDNZp16ATIdYckJnuav2gA Related Issues:

grumd commented 3 years ago

Pretty sure TS doesn't yet support typechecking that a part of a string is a number.

armondwillingham commented 3 years ago

Pretty sure TS doesn't yet support typechecking that a part of a string is a number.

It was just released in TS 4.1 with Template Literal Types

grumd commented 3 years ago

It was just released in TS 4.1 with Template Literal Types

I'm pretty sure it can only typecheck that a part of a string is certain kind of string, like for example

type Foo = `Bar${'Foo' | 'Bar'}`

The type inside of ${} must always be extends string

I don't think it can yet check for number inside a string. A part of a string is always another string. '1' is a string. Typescript doesn't support checking if this string can be safely converted into a number.

Or maybe I'm wrong and you can point me to a doc.

armondwillingham commented 3 years ago

I don't think it can yet check for number inside a string. A part of a string is always another string. '1' is a string. Typescript doesn't support checking if this string can be safely converted into a number.

Or maybe I'm wrong and you can point me to a doc.

https://www.typescriptlang.org/play?#code/C4TwDgpgBAdgrgWwEYQE4EkYGVioJYwDmAKuNALxQAGAhgM4AmAZgCQDe8yaAvlQNwAoAQBsIwKADcawvAwBcsRCgzZcBEmSiUA5PWYBGAEwBmACzbBo8QSkz5iripz4ipSFqi7GTPUwtCRMSg6XAA5RAUQl0IPbSMzfysHcIQFTmUPeNNLIJlgNGkAdTxgAAtnNKU0TGd1NwpqX3YolN4c8TyC4WKylMrHGrVXTUpab3ZOVv4hUHd0tAB5GGEQeo8qCarUNsDxTiWVgDVpWX7lA9WRzyzEoP3lkExbU4dzh7WdX1vxOlKAezgwgYACEIMc7GdFu8rhsOIgpnwgA

Does this help? It looks like if you make a type ${number} then when you assign a value to a variable with that type, it ensures that the string is a number, as long as you're assigning it directly, like val: `${number}` = '1234';.

If you try to do something more in depth, it seems like it breaks. For example, val: `${number}` = `${1234}`; doesn't compile, which is a shame because I feel like it removes most of the usefulness of Template Literal Types. This is the same for concatenation as well.

notpushkin commented 1 year ago

Here's a cool use case for this: type-checking fetch calls!

openapi-typescript can generate type definitions for OpenAPI schemas (with or without template literals for paths), and its sister project openapi-fetch provides a client for such definitions. Currently, you have to specify path parameters like this:

const client = createClient<paths>({ baseUrl: "https://myserver.com/api/v1/" });
client.get("/projects/{id}", { params: { paths: { id: 1 } });

With template literals, it could look like this instead:

client.get(`/projects/${1}`);

Sadly, paths with such parameters aren't suggested by TypeScript right now, so while this can still be used (e. g. for type checking and return type hints), it isn't as convenient (you can't just find the endpoint you need from autocomplete and need to type it in by hand).