Skip to content

Instantly share code, notes, and snippets.

@Gerrit0
Last active July 31, 2021 13:33
Show Gist options
  • Save Gerrit0/a01674100ceb93df31b9b60b8f0ec6e8 to your computer and use it in GitHub Desktop.
Save Gerrit0/a01674100ceb93df31b9b60b8f0ec6e8 to your computer and use it in GitHub Desktop.
Different subtype error explanation

The different subtype error is usually caused by two mistakes:

  1. Providing a default value which might not be specific enough.
function broke<T extends string>(x: T = "error"): T { return x }
//                               ^^^^^^^^^^^^^^
// Type 'string' is not assignable to type 'T'.
//  'string' is assignable to the constraint of type 'T', but
//  'T' could be instantiated with a different subtype of
//  constraint 'string'.

This isn't valid because someone can call your function as broke<"x">(), in which case the returned value must be "x" but the default can't determine this.

  1. Providing an implementation which allows the generic type to be limited too early.
interface Identity {
    identity<T>(x: T): T
}

class Child<T> implements Identity {
    identity(x: T): T { return x }
//  ^^^^^^^^
// Property 'identity' in type 'Child<T>' is not assignable
// to the same property in base type 'Identity'.
//   ...
//      Type 'T' is not assignable to type 'T'. Two different
//      types with this name exist, but they are unrelated.
//        'T' could be instantiated with an arbitrary type
//        which could be unrelated to 'T'.
}

This isn't valid, because even if I have a Child, I should be able to call identity with some other type.

const child = new Child<string>()
child.identity(11) // ok for Identity, but not for Child

Some rules of thumb to keep in mind:

  • Ensure the function works for all possible values of T. If T extends string, consider the user supplying T = string, T = "x", and T = never.
  • Review if the function must be generic.

Sometimes this error might theoretically be a problem, but you can guarantee that in reality, it will never be an issue. If so, you can use overloads to remove the subtype checking.

function broke<T extends string>(x?: T): T
function broke(x: string = "error"): string { // unsafe, no error
    return x;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment