Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error not issued when global type is an alias of an object type literal #57564

Open
rotu opened this issue Feb 27, 2024 · 6 comments
Open

Error not issued when global type is an alias of an object type literal #57564

rotu opened this issue Feb 27, 2024 · 6 comments
Labels
Bug A bug in TypeScript Has Repro This issue has compiler-backed repros: https://aka.ms/ts-repros
Milestone

Comments

@rotu
Copy link

rotu commented Feb 27, 2024

πŸ”Ž Search Terms

array, constructor, bracket

πŸ•— Version & Regression Information

  • This is a crash

⏯ Playground Link

https://www.typescriptlang.org/dev/bug-workbench/?noLib=true&target=99&ts=5.5.0-dev.20240227#code/PTAEAEDsHsBkEsBGAuUAXATgVwKYCgQI0BDDAcxzVRwGdIcAPNPPAExwGMAbUnUMrtETEuoAN55QoDtEg00oAIIYMxAJ6oJUqQB4AKqAC8oLJADWMAO6QAfAAoAdE9JkayYpDUBtALoBKVGVVNX0bSW16S1B9IxNzK0gAGnsnBxc3D29-QJV1UPCAXxYpNDUABz4gvL0bWK1tL3hUSCwAW0QcDB9UPXCpLhxIMjQAC2a2joxCvCKCMBFRaAAzdBG+DsEosngANz4AIgAFDGgKjFLQAHIBodHL0HgaUFbHmnghh8h0cr5LsQLLql9sg8ABuUB2LwARkSoAATLCAMz+UA0YhoR5LeC0JS5EItdqdGygsEQ6GwhGgZF+VHozHYp5iUA3YZjUAEyagAok9jcXjSWTyUCkKHNHB7DC+Uki2kYmhYnFMlmjcaEjBcnmcHgYPgyOQKUhw1WTKXgw2y+mK5mDVnGzpclhzVaPVEjaBYLisVYnKIeUCdE7qxBYBTwBSsaC0SCXZiEcBoGgAWkYFQ4aGTKmgU3BkJ8wqeHM6vhpaLlCqe8gw7zIUrwKazCiZBSAA

πŸ’» Code

// @noLib: true
// @target: esnext

declare global {
  const Array: {
    <T = unknown>(...args:any[]): Array<T>
    new <T = unknown,>(...args:any[]): Array<T>
  }

  type Array<T> = {
    [i: number]: T
    length: number
  }
}

// all of the below give "Property 'length' is missing in type '{}'...":
; ([1, 2, 3]) satisfies Array<number>;
; ([1, 2, 3]) satisfies { length: number };
declare const ar1: never[]
; ar1 satisfies { length: number };
declare const ar2: number[]
; ar2 satisfies { length: number }


// this should throw an error but it doesn't
// @ts-expect-error
; ([] as number[]) satisfies string[]

export { }

πŸ™ Actual behavior

Types created with the T[] and objects created with the [x as T] syntax are not typed as Array<T> but instead as {}.

πŸ™‚ Expected behavior

I expect either:

  • T[] syntax and Array<T> to be completely synonymous
  • A compiler error that the Array type is not an instantiable type

Additional information about the issue

Related to #57009.

@RyanCavanaugh RyanCavanaugh added the Not a Defect This behavior is one of several equally-correct options label Feb 27, 2024
@RyanCavanaugh
Copy link
Member

This is not supported. Array<T> must be an interface.

You're the only person trying to do this, please stop πŸ˜…

@rotu
Copy link
Author

rotu commented Feb 27, 2024

This is not supported. Array<T> must be an interface.

You're the only person trying to do this, please stop πŸ˜…

lol - gotcha. Wasn't sure if "this isn't going to work" was referring to the circular definition or using a type alias. Now I know!

I'm suprised there's not a compiler error - it seems like checker.ts should be checking the presence and the arity of the global Array type. There's even a check in there (that doesn't seem to be working) that global types are declared as a class or interface.

globalArrayType = getGlobalType("Array" as __String, /*arity*/ 1, /*reportErrors*/ true);

// ...

function getGlobalType(name: __String, arity: number, reportErrors: boolean): ObjectType | undefined {
    const symbol = getGlobalTypeSymbol(name, reportErrors);
    return symbol || reportErrors ? getTypeOfGlobalSymbol(symbol, arity) : undefined;
}

// ...

function getTypeOfGlobalSymbol(symbol: Symbol | undefined, arity: number): ObjectType {
    function getTypeDeclaration(symbol: Symbol): Declaration | undefined {
        const declarations = symbol.declarations;
        if (declarations) {
            for (const declaration of declarations) {
                switch (declaration.kind) {
                    case SyntaxKind.ClassDeclaration:
                    case SyntaxKind.InterfaceDeclaration:
                    case SyntaxKind.EnumDeclaration:
                        return declaration;
                }
            }
        }
    }

    if (!symbol) {
        return arity ? emptyGenericType : emptyObjectType;
    }
    const type = getDeclaredTypeOfSymbol(symbol);
    if (!(type.flags & TypeFlags.Object)) {
        error(getTypeDeclaration(symbol), Diagnostics.Global_type_0_must_be_a_class_or_interface_type, symbolName(symbol));
        return arity ? emptyGenericType : emptyObjectType;
    }
    if (length((type as InterfaceType).typeParameters) !== arity) {
        error(getTypeDeclaration(symbol), Diagnostics.Global_type_0_must_have_1_type_parameter_s, symbolName(symbol), arity);
        return arity ? emptyGenericType : emptyObjectType;
    }
    return type as ObjectType;
}

@RyanCavanaugh
Copy link
Member

Good catch; I think we changed how eagerly type aliases are resolved in some cases and broke that check.

@RyanCavanaugh RyanCavanaugh added Bug A bug in TypeScript and removed Not a Defect This behavior is one of several equally-correct options labels Feb 27, 2024
@RyanCavanaugh RyanCavanaugh changed the title Defining a type Array breaks [] syntax Error not issued when global type is an alias of an object type literal Feb 27, 2024
@typescript-bot typescript-bot added the Has Repro This issue has compiler-backed repros: https://aka.ms/ts-repros label Feb 27, 2024
@RyanCavanaugh
Copy link
Member

Gonna hijack this one

@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone Feb 27, 2024
@RyanCavanaugh
Copy link
Member

It looks like we created an unintentional dependency on this codepath not flagging type aliases when we added PromiseConstructorLike, which is defined as

declare type PromiseConstructorLike = new <T>(executor: (resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void) => PromiseLike<T>;

Maybe just telling people to not do this when they try to is sufficient; this function is now quite a bit indirected from different call sites that do/do not have the class/interface distinction.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 28, 2024

πŸ‘‹ Hi, I'm the Repro bot. I can help narrow down and track compiler bugs across releases! This comment reflects the current state of the repro in the issue body running against the nightly TypeScript.


Issue body code block by @rotu

❌ Failed: -

  • Type '{}' does not satisfy the expected type 'Array'. Property 'length' is missing in type '{}' but required in type 'Array'.
  • Type '{}' does not satisfy the expected type '{ length: number; }'. Property 'length' is missing in type '{}' but required in type '{ length: number; }'.
  • Type '{}' does not satisfy the expected type '{ length: number; }'. Property 'length' is missing in type '{}' but required in type '{ length: number; }'.
  • Type '{}' does not satisfy the expected type '{ length: number; }'. Property 'length' is missing in type '{}' but required in type '{ length: number; }'.
  • Unused '@ts-expect-error' directive.

Historical Information
Version Reproduction Outputs
4.9.3, 5.0.2, 5.1.3, 5.2.2, 5.3.2

❌ Failed: -

  • Type '{}' does not satisfy the expected type 'Array'. Property 'length' is missing in type '{}' but required in type 'Array'.
  • Type '{}' does not satisfy the expected type '{ length: number; }'. Property 'length' is missing in type '{}' but required in type '{ length: number; }'.
  • Type '{}' does not satisfy the expected type '{ length: number; }'. Property 'length' is missing in type '{}' but required in type '{ length: number; }'.
  • Type '{}' does not satisfy the expected type '{ length: number; }'. Property 'length' is missing in type '{}' but required in type '{ length: number; }'.
  • Unused '@ts-expect-error' directive.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Has Repro This issue has compiler-backed repros: https://aka.ms/ts-repros
Projects
None yet
Development

No branches or pull requests

3 participants