PatrykD
PatrykD

Reputation: 83

TypeScript custom type hint

I would like to declare few simple types, to distinguish strings like "url", "absolute url", "json", etc. It would be enough, to show declared type in hint, but type checking would be even better (i.e. "url" couldn't be passed to function expecting "absolute url").

The issue is that TypeScript/VSC understands, that "url" is a string and skips my declared type. Is there any way, to show declared type in hint? I don't mind hacky solutions as long as they don't break TypeScript features.

Sample code - I want to see "const data: url" in hint:

enter image description here

What I want to see (but this solution is bad, because url shouldn't be a number): enter image description here

Upvotes: 0

Views: 3189

Answers (3)

Karol Majewski
Karol Majewski

Reputation: 25820

Solution

Intersect your primitive type with an empty object type.

type url = string & {};

Explanation

Note that {} does not mean empty object as you may think. It represents everything but null | undefined. Here, mixing string with {} doesn't change anything, but the name will now be preserved.

Upvotes: 3

g2jose
g2jose

Reputation: 1465

There is no guarantee that your type aliases get preserved as typescript does not care if something is a string or a url as they have the same underlying type. This is due to the structural (as opposed to nominal) typing philosophy typescript adopts, although there are some proposals to support this use case (https://github.com/microsoft/TypeScript/pull/33038, https://github.com/microsoft/TypeScript/pull/33290).

Your best bet in the mean time is to use a function with a return type like so:

working code

As for your other question - different url types - you can achieve something like this using discriminated unions & adding properties to the string object:

type url = string & { _subtype: 'absoluteUrl' | 'relativeUrl' | 'other' }
type absoluteUrl = url & { _subtype: 'absoluteUrl' }
type relativeUrl = url & { _subtype: 'relativeUrl' }

const createAbsoluteUrl = (input: string) => {
  const createdAbsoluteUrl = input
  ;(createdAbsoluteUrl as any)._subtype = 'absoluteUrl'
  return createdAbsoluteUrl as absoluteUrl
}

const createRelativeUrl = (input: string) => {
  const createdRelativeUrl = input
  ;(createdRelativeUrl as any)._subtype = 'relativeUrl'
  return createdRelativeUrl as relativeUrl
}

const expectAbsoluteUrl = (input: absoluteUrl) => {
  // something
}

const expectRelativeUrl = (input: relativeUrl) => {
  // something
}

You should then see type errors as you expect: enter image description here

You may also find user defined type guards useful if you go with this approach

Upvotes: 2

Steve
Steve

Reputation: 602

I didn't find a hack to achieve something you've asked for using primitive types. But don't you mind using enum?

As a pros you will have your Url's in one place.

enter image description here

Upvotes: 1

Related Questions