Skip to content

Use extends on a variable declaration #36778

@gincher

Description

@gincher

Search Terms

extends, generic

Suggestion

Add self extends as a possible type for a variable, which acts like extends in generic - typechecks, but not sets a type.

Eg:

// Invalid
const func: self extends Function = "hello"; 

// Valid
const obj: self extends Object = {firstName: "John", lastName: "Doe"}; 
// typeof obj will return {firstName: string, lastName: string}

Use Cases

I want to extend Jest's matchers. Jest's website suggests duplicating code - creating an interface to extend the matchers interface, and separately, extend the matchers themselves.

What I did is create a function with a generic parameter that returns itself, and the generic is required (using <T extends ...>) to be a record with a function that returns Jest's CustomMatcherResult, which is to enforce the typing required for expect.extend(). Below, I extended Jest's Matchers interface with the object (after modifying it).

Examples

Currently can be achieved by:

// The function will simply return the first argument.
const PermissionExtends = <T extends Record<string, {guest: boolean, user: boolean, admin: boolean>}>(v: T) => v;
const permissions = PermissionExtends({
    readMessage: {guest: true, user: true, admin: true},
    writeMessage: {guest: false, user: true, admin: true},
    deleteMessage: {guest: false, user: false, admin: true}
});
type Permissions = keyof typeof permissions;
// Permissions = 'readMessage' | 'writeMessage' | 'deleteMessage'

Ideally:

const permissions: self extends Record<string, {guest: boolean, user: boolean, admin: boolean> = {
    readMessage: {guest: true, user: true, admin: true},
    writeMessage: {guest: false, user: true, admin: true},
    deleteMessage: {guest: false, user: false, admin: true}
};
type Permissions = keyof typeof permissions;
// Permissions = 'readMessage' | 'writeMessage' | 'deleteMessage'

Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions