Skip to content
This repository was archived by the owner on Jan 19, 2019. It is now read-only.

Add typed heritage parameters to class conversion #44

Closed
nzakas opened this issue Jul 8, 2016 · 7 comments
Closed

Add typed heritage parameters to class conversion #44

nzakas opened this issue Jul 8, 2016 · 7 comments
Labels

Comments

@nzakas
Copy link
Member

nzakas commented Jul 8, 2016

It's possible to do things like:

class Foo implements Bar<S> {

}

Right now, we completely lose the S part of the conversion. We should mimic what TypeScript does to remedy this.

@nzakas nzakas added the bug label Jul 8, 2016
@JamesHenry
Copy link
Member

JamesHenry commented Aug 9, 2016

As discussed, here is a proposed AST result for the code above.

The logic will involve converting the relevant TSNode's typeArguments array to a typeParameters node (to match flow).

module.exports = {
    "type": "Program",
    "range": [
        0,
        32
    ],
    "loc": {
        "start": {
            "line": 1,
            "column": 0
        },
        "end": {
            "line": 3,
            "column": 1
        }
    },
    "body": [
        {
            "type": "ClassDeclaration",
            "range": [
                0,
                32
            ],
            "loc": {
                "start": {
                    "line": 1,
                    "column": 0
                },
                "end": {
                    "line": 3,
                    "column": 1
                }
            },
            "id": {
                "type": "Identifier",
                "range": [
                    6,
                    9
                ],
                "loc": {
                    "start": {
                        "line": 1,
                        "column": 6
                    },
                    "end": {
                        "line": 1,
                        "column": 9
                    }
                },
                "name": "Foo"
            },
            "body": {
                "type": "ClassBody",
                "body": [],
                "range": [
                    28,
                    32
                ],
                "loc": {
                    "start": {
                        "line": 1,
                        "column": 28
                    },
                    "end": {
                        "line": 3,
                        "column": 1
                    }
                }
            },
            "superClass": null,
            "implements": [
                {
                    "type": "ClassImplements",
                    "loc": {
                        "start": {
                            "line": 1,
                            "column": 21
                        },
                        "end": {
                            "line": 1,
                            "column": 24
                        }
                    },
                    "range": [
                        21,
                        24
                    ],
                    "id": {
                        "type": "Identifier",
                        "range": [
                            21,
                            24
                        ],
                        "loc": {
                            "start": {
                                "line": 1,
                                "column": 21
                            },
                            "end": {
                                "line": 1,
                                "column": 24
                            }
                        },
                        "name": "Bar"
                    },
                    "typeParameters": {
                        "type": "TypeParameterInstantiation",
                        "range": [
                            24,
                            27
                        ],
                        "loc": {
                            "start": {
                                "line": 1,
                                "column": 24
                            },
                            "end": {
                                "line": 1,
                                "column": 27
                            }
                        },
                        "params": [
                            {
                                "type": "GenericTypeAnnotation",
                                "range": [
                                    25,
                                    26
                                ],
                                "loc": {
                                    "start": {
                                        "line": 1,
                                        "column": 25
                                    },
                                    "end": {
                                        "line": 1,
                                        "column": 26
                                    }
                                },
                                "id": {
                                    "type": "Identifier",
                                    "range": [
                                        25,
                                        26
                                    ],
                                    "loc": {
                                        "start": {
                                            "line": 1,
                                            "column": 25
                                        },
                                        "end": {
                                            "line": 1,
                                            "column": 26
                                        }
                                    },
                                    "name": "S"
                                },
                            }
                        ]
                    }
                }
            ]
        }
    ],
    "sourceType": "script",
    "tokens": [
        {
            "type": "Keyword",
            "value": "class",
            "range": [
                0,
                5
            ],
            "loc": {
                "start": {
                    "line": 1,
                    "column": 0
                },
                "end": {
                    "line": 1,
                    "column": 5
                }
            }
        },
        {
            "type": "Identifier",
            "value": "Foo",
            "range": [
                6,
                9
            ],
            "loc": {
                "start": {
                    "line": 1,
                    "column": 6
                },
                "end": {
                    "line": 1,
                    "column": 9
                }
            }
        },
        {
            "type": "Keyword",
            "value": "implements",
            "range": [
                10,
                20
            ],
            "loc": {
                "start": {
                    "line": 1,
                    "column": 10
                },
                "end": {
                    "line": 1,
                    "column": 20
                }
            }
        },
        {
            "type": "Identifier",
            "value": "Bar",
            "range": [
                21,
                24
            ],
            "loc": {
                "start": {
                    "line": 1,
                    "column": 21
                },
                "end": {
                    "line": 1,
                    "column": 24
                }
            }
        },
        {
            "type": "Identifier",
            "value": "S",
            "range": [
                25,
                26
            ],
            "loc": {
                "start": {
                    "line": 1,
                    "column": 25
                },
                "end": {
                    "line": 1,
                    "column": 26
                }
            }
        },
        {
            "type": "Punctuator",
            "value": "{",
            "range": [
                28,
                29
            ],
            "loc": {
                "start": {
                    "line": 1,
                    "column": 28
                },
                "end": {
                    "line": 1,
                    "column": 29
                }
            }
        },
        {
            "type": "Punctuator",
            "value": "}",
            "range": [
                31,
                32
            ],
            "loc": {
                "start": {
                    "line": 3,
                    "column": 0
                },
                "end": {
                    "line": 3,
                    "column": 1
                }
            }
        }
    ]
};

@nzakas
Copy link
Member Author

nzakas commented Aug 9, 2016

Yeah, I think overall what we're talking about is adding the typeParameters property, which has a TypeParameterInstantiation node with a params property containing type annotations. We probably want to double-check if it's possible for anything other than GenericTypeAnnotation to be in that array.

Also, it looks like you're missing the < and > tokens in the token array. Those should be punctuators.

@JamesHenry
Copy link
Member

Thanks 👍 I'll try my best to hunt down info on GenericTypeAnnotation

@JamesHenry
Copy link
Member

Not an abundance of info around, but I think this might be a good resource: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/estree/flow.d.ts

It suggests that TypeParameterInstantiation's params array is just Array<FlowTypeAnnotation>, but rather unhelpfully the only definition of FlowTypeAnnotation is

interface FlowTypeAnnotation extends Node {}

In my initial implementation, typeArguments are only being converted to typeParameters in the specific case of class implements, so perhaps we can accept this as an initial resolution?

I have also added another case for multiple types in the generic:

class Foo implements Bar<S, T> {

}

@JamesHenry
Copy link
Member

JamesHenry commented Aug 9, 2016

Ah, I'm glad I did that because it raises an interesting question:

TypeScript includes the whitespace in front of the T in <S, T> in its range numbers, flow does not.

Shall we favour the flow approach here and "trim" the whitespace in some way when converting the node?

We can manually discount the whitespace by doing something like this when processing the TypeScript typeArgument:

var typeArgumentStart = (typeArgument.typeName && typeArgument.typeName.text)
      ? typeArgument.end - typeArgument.typeName.text.length
      : typeArgument.pos;

@JamesHenry
Copy link
Member

I have to break off now, but I have gone ahead and opened a PR to finalise the discussion for this issue #53

Thanks for your help!

@nzakas
Copy link
Member Author

nzakas commented Aug 10, 2016

Yes, the nodes/tokens should not include whitespace.

@nzakas nzakas closed this as completed in 62d14b4 Aug 10, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

2 participants