Skip to content

Infer literal types for string concatenations and similar expressions #13969

Closed
@donaldpipowitch

Description

@donaldpipowitch

TypeScript Version: 2.1.5

Expected behavior:

const foo = 'world'; // value type: 'world'
const bar = `hello ${foo}`; // value type: 'hello world'

Actual behavior:

const foo = 'world'; // value type: 'world'
const bar = `hello ${foo}`; // type: 'string'

Motivation

For constants which are created from other constants the IntelliSense is often more useful, when we see its value type instead of the "real" type.

More practical example:

const fooBreakpoint = '800px';
const fooMediaQuery = `@media(min-width: ${fooBreakpoint})`;

When fooMediaQuery is used I'd like to see @media(min-width: 800px) as its type instead of string.

Activity

added
Awaiting More FeedbackThis means we'd like to hear from more people who would be helped by this feature
SuggestionAn idea for TypeScript
on Feb 9, 2017
DanielRosenwasser

DanielRosenwasser commented on Feb 9, 2017

@DanielRosenwasser
Member

When fooMediaQuery is used I'd like to see @media(min-width: 800px) as its type instead of string.

This is interesting, mostly because it sounds like you are leveraging your editor's support of string literal types so that you can quickly glance at a type and get its content.

donaldpipowitch

donaldpipowitch commented on Feb 9, 2017

@donaldpipowitch
ContributorAuthor

Yeah, when I work with CSS-in-JS solutions like glamor it is so great to immediately see some concrete value for different constants instead of just number or string.

import { css } from 'glamor';

const color = '#fff';
const mq = '@media(min-width: 800px)';

const myStyle = css({
  [mq]: {  // hover over `mq` → see '@media(min-width: 800px)'
    color  // hover over `color` → see '#fff'
  }
});

If infering the value type doesn't work (e.g. because of templated strings) I need to duplicate the information into a comment which of course easily gets out of date, if someone changes the values without changing the comment.

import { css } from 'glamor';

const color = '#fff';
const breakpoint = '800px';
/**
 * The media query is '@media(min-width: 800px)'.
 */
const mq = `@media(min-width: ${breakpoint})`;

const myStyle = css({
  [mq]: {  // hover over `mq` → see 'string' as its type and the comment which shows the value
    color  // hover over `color` → see '#fff'
  }
});
changed the title [-]Infer value type for easy expresssions[/-] [+]Infer literal types for string concatenations and similar expressions[/+] on Jun 16, 2017
fjmorel

fjmorel commented on Apr 12, 2018

@fjmorel

I'd like to be able to do something like this, building a key using string literals:

type Obj = Record<"a" | "a1" |  "b" | "b1", string>;

function getKey(useA: boolean, useOne: boolean): keyof Obj {
  // [ts] Type 'string' is not assignable to type '"a" | "a1" | "b" | "b1"'.
  return (useA ? "a" : "b") + (useOne ? "1" : "");
}

Adding a cast after the string concatenation makes the error go away, but doesn't actually check that my key generation is still valid if I change Obj.

ethanresnick

ethanresnick commented on Dec 8, 2018

@ethanresnick
Contributor

Similar to @fjmorel, I'd love to have this distribute over a union. My use case is basically:

// i don't control the shape of x.
const x = { item1: true, item2: false, item3: true };

([1, 2, 3] as (1 | 2 | 3)[]).forEach(itemNum => {
    // would love type inference here as item1 | item2 | item3
    const itemKey = `item${itemNum}`;
});
ascott18

ascott18 commented on Aug 21, 2019

@ascott18

This would be fantastic to see for indexing into objects with string literals, especially now that const assertions have been added in 3.4.

const obj= {
 sourceName: "source",
 sourceId: 1,
 targetName: "target",
 targetId: 2,
}

function getValues(prefix: "source" | "target") {
 return { name: obj[prefix + "Name"], id: obj[prefix + "Id"] }
}
vdh

vdh commented on Jan 13, 2020

@vdh

It'd be nice to be able to use either string literals or unions.

const bar = "bar";
const foobar = `foo${bar}`; // "foobar"
let union: "bar" | "baz";
const foobarOrFoobaz = `foo${union}`; // "foobar" | "foobaz"
let generic: string;
const stillGeneric = `foo${generic}`; // string
mortoray

mortoray commented on Jun 16, 2020

@mortoray

This would be helpful for string enums with a common prefix.

const prefix = "mymodule_"
export enum Actions {
  actionOne: prefix + "action_one"
  actionTwo: prefix + "action_two"
}

This is currently rejected with error TS2553: Computed values are not permitted in an enum with string valued members.

vdh

vdh commented on Jul 27, 2020

@vdh

Maybe a const assertion syntax would suit this?

const bar = "bar"; // "bar"
const existingBehaviour = `foo-${bar}`; // string
const dynamic = process.env.BAR; // string | undefined
const existingBehaviourDynamic = `foo-${dynamic}`; // string
const barOrBaz = Math.round(Math.random()) ? "bar" : "baz"; // "bar" | "baz"
// A const assertion syntax…?
const fooBar = `foo-${bar}` as const; // "foo-bar"
const fooBarOrBaz = `foo-${barOrBaz}` as const; // "foo-bar" | "foo-baz"
const badDynamicVariable = `foo-${dynamic}` as const; // type error
jcalz

jcalz commented on Sep 3, 2020

@jcalz
Contributor

this is not inferred yet, but now we at least have #40336 to represent string concatenation at the type level,

bradzacher

bradzacher commented on Nov 18, 2022

@bradzacher
Contributor
jakebailey

jakebailey commented on Apr 8, 2024

@jakebailey
Member

This was fixed in #53907, which I believe has enough testing for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Awaiting More FeedbackThis means we'd like to hear from more people who would be helped by this featureSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @jcalz@ethanresnick@vdh@DanielRosenwasser@donaldpipowitch

        Issue actions

          Infer literal types for string concatenations and similar expressions · Issue #13969 · microsoft/TypeScript