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

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

Closed
9SMTM6 opened this issue Nov 1, 2018 · 4 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@9SMTM6
Copy link

9SMTM6 commented Nov 1, 2018

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:

@weswigham
Copy link
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 weswigham added the Question An issue which isn't directly actionable in code label Nov 1, 2018
@weswigham
Copy link
Member

weswigham commented Nov 1, 2018

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
Copy link
Author

9SMTM6 commented Nov 1, 2018

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
Copy link
Collaborator

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

3 participants