Repository: TypeScript
Issue: Type metadata / shadow types
Labels: Suggestion,Awaiting More Feedback

# Suggestion

## 🔍 Search Terms

type metadata info secondary

## ✅ Viability Checklist

My suggestion meets these guidelines:

* [x] This wouldn't be a breaking change in existing TypeScript/JavaScript code
* [x] This wouldn't change the runtime behavior of existing JavaScript code
* [x] This could be implemented without emitting different JS based on the types of the expressions
* [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
* [x] This feature would agree with the rest of [TypeScript's Design Goals](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals).

## ⭐ Suggestion

Create a type that in a union, has no effect on the result of the union (same as never), but can be retrieved using a special type (i.e. `GetMetadata<T>`).

```ts
type x = number | Metadata<unknown>; // type is: number
type metaX = GetMetadata<x>; // type is unknown
```

## 📃 Motivating Example

This can be used to document errors which a function may throw.

Currently, Typescript allows to do something like the below, but there's an issue in that the Throws<> type pollutes the function return type which has to be manually eliminated by type casting - not very practical.

This is a full example of what I'm aiming at, from my comment in the issue https://github.com/microsoft/TypeScript/issues/13219#issuecomment-928866237

```ts
type Throws<T> = { throws: T };

type GetThrow<T> = T extends Throws<infer R> ? R : never;
type GetResult<T> = T extends Throws<unknown> ? never : T;

type GetFunctionThrow<T extends (...args: any[]) => any> = GetThrow<ReturnType<T>>;
type GetFunctionResult<T extends (...args: any[]) => any> = GetResult<ReturnType<T>>;

type CalcError = {
    code: "calc_error"
    message: string
}

type DivisionError = {
    code: 'division_error'
    message: string
}

function divide(a: number, b: number): number | Throws<DivisionError> {
    if (b === 0) {
        throw { code: "division_error", message: "Cannot divide by 0" } as DivisionError; 
    }

    return a / b;
}

function calc(a: number, b: number, operation: 'divide'): number | Throws<CalcError | DivisionError> {
    if (typeof a !== 'number' || typeof b !== 'number') {
        throw { code: "calc_error", message: "Required 2 number arguments" } as CalcError;
    }

    if (operation !== 'divide') {
        throw { code: "calc_error", message: "Unsupported operation" } as CalcError;
    }

    return divide(a,b);
}

let x: number;

try {
    // This casting makes this method hardly practical. If we had a metadata type, it would be a number by default.
    x = calc(5 ,6, 'divide') as GetFunctionResult<typeof calc>;
} catch (e: unknown) { // Catch-clause annotation must be any or unknown
    const err = e as GetFunctionThrow<typeof calc>; // CalcError | DivisionError
}
```
[Playground](https://www.typescriptlang.org/play?#code/C4TwDgpgBAKgFgJwPYHcDOAeGA+KBeKAbymEVTQC5YoBfAbgCgHRIoBxCYeZFLXAmFAgAPYBAB2AEzSwy6DAEtxAMwgIoAJVwB+TVCriIANzWMW0DsA0Q0AVwA2wPvmoixUmd3IZb4gNbiqOI6UIYm6lQwjMzgFpwAYr4AxsAKSOJevIJuEtJQABQAdMUAhggA5pRQJeIgANoAugCU+Lg1IPzsnJkY1sC2CBmxfNhmsV3AieIpaeLWdo5YQqK5MkWlFVXtjS14bbWdlvMOTn0DQ5Aj0eZQAMIl9kkAogjI6gSEDFDfUElIkhAqAAiJIPJIAfTUbyBXx+AFsbGgSuVAVA0MAEEpygwaEwbgARBRGBRoWYvN4uT4-X7-VEAckkRJJs0hryQCDpsO+CLQSJRVHRmPE2NxDGUyVS6SgjOJAPyJQMtjhACM1AAaKDKxUqtRNbWq9QAH1kPEwhOJpPS5PZuCpPwUygKyvweAIAAYWnbqd9SDwiDSAcCZcz0qzoRqeXzUUD7uJAsBpUyAZqQFA3UDaNUZOaQ+JrQg6FAubQmNSEJxztUoAB6TWMUXi6aS8S-MHy-XqzUdhAapCQBAlZtUBlJiB0vWhJUGqDGzKYe6PfMzqA5y15tkIW3Fh0FcxIR0lKAAQldUDp4inajpM+Ne8dzpPBHPl45nuL1N9qH9f0DUBBYLDdkgQjRFkWjawAEdbAUctJCgAAmScdXUMpyiVCRgDQDMaCzO4wXzRhqVFakd3yPs1EHWZj1PEdZTHN9vR+T8UG-WlgVBR5AIQYCoEjMDgQAVXEOwwDAdkxDg8iB2bbDcIXZ4N0In5iJ+ct+kGRM6PlNVlSaesmHsTgoGEbtrgQVMvRrWt4BJVt0SxXiSj8GwSDgWyEVIf4oDgMpJHsVMwAHGYOMKKAAElHRQaAfLgw8PJKSRB0PcwNQUBMUCQBw4NVKsL2QlNpQgZQShOQpi2EFwOKSfIAFYoDVAA2DVaIUAFx1wywphmdJjkWO9W0eUYcVbYAkjgApUV8AIgk9Ky8NGuAAFoknsEq0GgGp40oqU4VsdFNQ22ooHZKApsCFBxGLP5hITKEXA2mROolWYen6qrRjm+Sl2NVcyQ3HEgA)

With the new special `Metadata<T>` utility type it would possible to store such information and access it with a special type `GetMetadata<T>` while the type like `number | string | Metadata<unknown>` would be just `number | string`. 


## 💻 Use Cases

1. What do you want to use this for?
   Documenting what types of errors a function may throw.

2. What shortcomings exist with current approaches?
    It's possible to use a helper type to eliminate the metadata from the union, but it's too verbose to be practical.  It could also be stored in a separate type, but with classes, it would be away from the method body and also not practical enough to consider.

3. What workarounds are you using in the meantime?
   I'm not documenting the types of errors a function may throw at all or I use tsdoc throws (but it does not allow to store type info).