#How do I enforce template strings such that possibilities are more restricted

10 messages · Page 1 of 1 (latest)

royal mothBOT
#
tickleme_pink#0

Preview:```ts
interface String {
toUpperCase<T extends string>(this: T): Uppercase<T>
toLowerCase<T extends string>(this: T): Lowercase<T>
}

type Movie = typeof movies[number]
const movies = [
{
name: "Waterboy",
year: "1998",
},
{
name: "WeddingSinger"
...```

ocean shoal
#

I suppose a more concise version would be: ```type O =
| {
a: "a";
b: "b";
}
| { a: "y"; b: "z" };

const makeKey = (o: O) => ${o.a}-${o.b} as const;
//const makeKey: (o: O) => "a-b" | "a-z" | "y-b" | "y-z" -- Impossible combinations.```

fallen hedge
#

FWIW this behavior is not specific to template literals. it's just that typescript doesn't really keep track of correlations between property values as thoroughly as you'd want

#

here's a template-less example:

royal mothBOT
#
type A = { a: string, b: string } | { a: number, b: number }
const f = (a: A) => [a.a, a.b] as const
//    ^? - const f: (a: A) => readonly [string | number, string | number]
fallen hedge
#

you'd want f to return [string, string] | [number, number]

#

generally when you encounter this situation you either have to "pointlessly" narrow the value first like this:

royal mothBOT
#
type O =
  | {
      a: "a";
      b: "b";
    }
  | { a: "y"; b: "z" };

const makeKey = (o: O) => (o.a === 'a') ?  `${o.a}-${o.b}` as const :  `${o.a}-${o.b}` as const
//    ^? - const makeKey: (o: O) => "a-b" | "y-z"
fallen hedge
#

or use a type assertion, like this:

royal mothBOT
#
type O =
  | {
      a: "a";
      b: "b";
    }
  | { a: "y"; b: "z" };

type SpecificCombinations<O extends { a: string, b: string }> =
  O extends O ? // distribute over the union
    `${O['a']}-${O['b']}`
  : never

const makeKey = (o: O) => `${o.a}-${o.b}` as SpecificCombinations<O>