镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Compiler is forgetting the basetype of an extended type when that type is generic #28280

Description

@9SMTM6

I have only done TS for about a 3/4 of a month, and JS for less than 2 months, so maybe I'm just doing someting fundamentally wrong, but after questioning people that have done this for some time I think these are some compiler-issues.

On an somewhat related note, if any of you managed to implement the 'Basic example' from here in TS without errors or using //ts-ignore please let me know. Also why is 'Proxy' in the ES2015 lib and not in the 'ES6' lib, and whats the difference between these libs?

TypeScript Version: 3.1.5 and 3.2.0-dev.20181101

Search Terms: generic, extend, extended, base-type, basetype, type

Code

// ------------------- with generic type -------------------//
const extGenTypeFactory = <TObj extends Object>(specialObj: TObj) => {
    /**
     * Throws 'TS2312: An interface may only extend a class or another interface.'. 
     * Doesnt compile the stuff using the interfaces and themself
     */
    interface TExtObj extends TObj {
        newAttr: any
    }
    // works
    let newObj = specialObj;

    let extObj: TExtObj
    // This particular issue is Solved in 3.2, keeping it for understanding of the comment line
    // TS2698: 'Spread types may only be created from object types.'. 
    extObj = {
        ...specialObj,
        newAttr: "some other"
    }
    return extObj
}

// Tried to evade problem with suggestion from 'Why doesn't type inference work on this interface: interface Foo<T> { } ?'
const obj = extGenTypeFactory({ attr: "take that" })

// works fine
const genTypeFactory= <TObj>(specialObj: TObj) => {
    return specialObj;
}
// \------------------- with generic type -------------------//

// ------------------- with known type -------------------//
interface TObj extends Object {
    hasAttr: any
}
/**
 * Works fine.
 */
interface TExtObj extends TObj {
    newAttr: any
}
// \------------------- with known type -------------------//

Expected behavior:
Compiles without error
Actual behavior:
Throws TS2312 and TS2698
Playground Link:

Related Issues:

Activity

weswigham commented on Nov 1, 2018

@weswigham
Member

Also why is 'Proxy' in the ES2015 lib and not in the 'ES6' lib, and whats the difference between these libs?

ES2015 is es6. When es6 was published they formally started a by-year versioning scheme; so es6 and es2015 are synonymous.

weswigham commented on Nov 1, 2018

@weswigham
Member

Secondly: An interface cannot inherit from a variable type parameter. If you want similar behavior, you want to use intersection types, like so:

    type TExtObj = TObj & {
        newAttr: any
    }

Thirdly: Capital O Object refers to the global Object constructor base type. You probably don't want that - you probably want the object (lower case o) primitive instead.

Fourth: Spreads are currently limited to concrete types - you cannot spread a generic. This will change in 3.2, thanks to #28234.

9SMTM6 commented on Nov 1, 2018

@9SMTM6
Author

ES2015 is es6. When es6 was published they formally started a by-year versioning scheme; so es6 and es2015 are synonymous.

Well, this is embarassing. Other than what you might think I am capable of performing a google search, so when i got an Cannot find name error on an Proxy keyword while having es6 in the libs variable of the tsconfig, I was really out of my depth. Even more so when I tried it with es2015 and it worked. But upon retry es6 works perfectly, so it mustve been an user error somewhere.

Secondly: An interface cannot inherit from a variable type parameter

Well yeah, thats more or less what I'm saying. Do you mean to say that this is by design? Why would you want to do that? Note that the variable type will always be an extension of object. The problem is that the compiler isnt smart enough to notice that, at least from what I think to see there.

Thanks for the hint with the intersection types. It could very well work, I'll try and report back.

Thirdly: Capital O Object refers to the global Object constructor base type. You probably don't want that - you probably want the object (lower case o) primitive instead.

Using object will throw Cannot find name at the reproduction with Interfaces below. {} Will throw a more understandable An object can only extend an identifier/qualified-name with optional type arguments, eventually I got to Object which worked. I guess cause its not a simple object. But true, its not really what i want here... didnt think any further about it after that worked.

Fourth: Spreads are currently limited to concrete types - you cannot spread a generic. This will change in 3.2, thanks to #28234.

Good to know, thanks. Hard to test though, as the issue described above is causing issues (Compiler specifically says that its not an object not only upon use of the spread operator but also the interface inheritance.), and here the Compiler of course already resolved it:

const genTypeFactory = <T>(param: T) => {
    return param;
}

const reWrapped = {...genTypeFactory({attr: "someVal"})}

EDIT: Actually I just tested it with the 3.2.0-dev.20181101. The spread-issue is gone indeed, the other issues remain. And the spread operation wasnt really a problem of mine, It was just something I tried to see if other operations I'd expect to work on an object worked.

typescript-bot commented on Jul 13, 2019

@typescript-bot
Contributor

This issue has been marked as 'Question' and has seen no recent activity. It has been automatically closed for house-keeping purposes. If you're still waiting on a response, questions are usually better suited to stackoverflow.

locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    QuestionAn issue which isn't directly actionable in code

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions