mirror of
https://github.com/github/codeql.git
synced 2025-12-22 19:56:32 +01:00
JS: Add TemplateLiteralTypeExpr
This commit is contained in:
@@ -43,6 +43,7 @@ import com.semmle.ts.ast.OptionalTypeExpr;
|
|||||||
import com.semmle.ts.ast.ParenthesizedTypeExpr;
|
import com.semmle.ts.ast.ParenthesizedTypeExpr;
|
||||||
import com.semmle.ts.ast.PredicateTypeExpr;
|
import com.semmle.ts.ast.PredicateTypeExpr;
|
||||||
import com.semmle.ts.ast.RestTypeExpr;
|
import com.semmle.ts.ast.RestTypeExpr;
|
||||||
|
import com.semmle.ts.ast.TemplateLiteralTypeExpr;
|
||||||
import com.semmle.ts.ast.TupleTypeExpr;
|
import com.semmle.ts.ast.TupleTypeExpr;
|
||||||
import com.semmle.ts.ast.TypeAliasDeclaration;
|
import com.semmle.ts.ast.TypeAliasDeclaration;
|
||||||
import com.semmle.ts.ast.TypeAssertion;
|
import com.semmle.ts.ast.TypeAssertion;
|
||||||
@@ -368,6 +369,11 @@ public class DefaultVisitor<C, R> implements Visitor<C, R> {
|
|||||||
return visit((Expression) nd, c);
|
return visit((Expression) nd, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public R visit(TemplateLiteralTypeExpr nd, C c) {
|
||||||
|
return visit((TypeExpression) nd, c);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public R visit(TaggedTemplateExpression nd, C c) {
|
public R visit(TaggedTemplateExpression nd, C c) {
|
||||||
return visit((Expression) nd, c);
|
return visit((Expression) nd, c);
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import com.semmle.ts.ast.OptionalTypeExpr;
|
|||||||
import com.semmle.ts.ast.ParenthesizedTypeExpr;
|
import com.semmle.ts.ast.ParenthesizedTypeExpr;
|
||||||
import com.semmle.ts.ast.PredicateTypeExpr;
|
import com.semmle.ts.ast.PredicateTypeExpr;
|
||||||
import com.semmle.ts.ast.RestTypeExpr;
|
import com.semmle.ts.ast.RestTypeExpr;
|
||||||
|
import com.semmle.ts.ast.TemplateLiteralTypeExpr;
|
||||||
import com.semmle.ts.ast.TupleTypeExpr;
|
import com.semmle.ts.ast.TupleTypeExpr;
|
||||||
import com.semmle.ts.ast.TypeAliasDeclaration;
|
import com.semmle.ts.ast.TypeAliasDeclaration;
|
||||||
import com.semmle.ts.ast.TypeAssertion;
|
import com.semmle.ts.ast.TypeAssertion;
|
||||||
@@ -419,6 +420,11 @@ public class NodeCopier implements Visitor<Void, INode> {
|
|||||||
return new TemplateLiteral(visit(nd.getLoc()), copy(nd.getExpressions()), copy(nd.getQuasis()));
|
return new TemplateLiteral(visit(nd.getLoc()), copy(nd.getExpressions()), copy(nd.getQuasis()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TemplateLiteralTypeExpr visit(TemplateLiteralTypeExpr nd, Void q) {
|
||||||
|
return new TemplateLiteralTypeExpr(visit(nd.getLoc()), copy(nd.getExpressions()), copy(nd.getQuasis()));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TaggedTemplateExpression visit(TaggedTemplateExpression nd, Void q) {
|
public TaggedTemplateExpression visit(TaggedTemplateExpression nd, Void q) {
|
||||||
return new TaggedTemplateExpression(
|
return new TaggedTemplateExpression(
|
||||||
|
|||||||
@@ -21,20 +21,23 @@ public class TemplateLiteral extends Expression {
|
|||||||
super("TemplateLiteral", loc);
|
super("TemplateLiteral", loc);
|
||||||
this.expressions = expressions;
|
this.expressions = expressions;
|
||||||
this.quasis = quasis;
|
this.quasis = quasis;
|
||||||
this.children = mergeChildren(expressions, quasis);
|
this.children = TemplateLiteral.<Expression>mergeChildren(expressions, quasis);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Merge quasis and expressions into a single array in textual order.
|
* Merge quasis and expressions into a single array in textual order.
|
||||||
* Also filter out the empty constant strings that the parser likes to generate.
|
* Also filter out the empty constant strings that the parser likes to generate.
|
||||||
*/
|
*/
|
||||||
private List<Expression> mergeChildren(
|
@SuppressWarnings("unchecked")
|
||||||
List<Expression> expressions, List<TemplateElement> quasis) {
|
public static <E extends INode> List<E> mergeChildren(
|
||||||
List<Expression> children = new ArrayList<Expression>();
|
List<? extends INode> expressions,
|
||||||
|
List<TemplateElement> quasis) {
|
||||||
|
|
||||||
|
List<INode> children = new ArrayList<INode>();
|
||||||
int j = 0, n = quasis.size();
|
int j = 0, n = quasis.size();
|
||||||
|
|
||||||
for (int i = 0, m = expressions.size(); i < m; ++i) {
|
for (int i = 0, m = expressions.size(); i < m; ++i) {
|
||||||
Expression expr = expressions.get(i);
|
INode expr = expressions.get(i);
|
||||||
for (; j < n; ++j) {
|
for (; j < n; ++j) {
|
||||||
TemplateElement quasi = quasis.get(j);
|
TemplateElement quasi = quasis.get(j);
|
||||||
if (quasi.getLoc().getStart().compareTo(expr.getLoc().getStart()) > 0) break;
|
if (quasi.getLoc().getStart().compareTo(expr.getLoc().getStart()) > 0) break;
|
||||||
@@ -48,7 +51,7 @@ public class TemplateLiteral extends Expression {
|
|||||||
if (!quasi.getRaw().isEmpty()) children.add(quasi);
|
if (!quasi.getRaw().isEmpty()) children.add(quasi);
|
||||||
}
|
}
|
||||||
|
|
||||||
return children;
|
return (List<E>)children;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import com.semmle.ts.ast.OptionalTypeExpr;
|
|||||||
import com.semmle.ts.ast.ParenthesizedTypeExpr;
|
import com.semmle.ts.ast.ParenthesizedTypeExpr;
|
||||||
import com.semmle.ts.ast.PredicateTypeExpr;
|
import com.semmle.ts.ast.PredicateTypeExpr;
|
||||||
import com.semmle.ts.ast.RestTypeExpr;
|
import com.semmle.ts.ast.RestTypeExpr;
|
||||||
|
import com.semmle.ts.ast.TemplateLiteralTypeExpr;
|
||||||
import com.semmle.ts.ast.TupleTypeExpr;
|
import com.semmle.ts.ast.TupleTypeExpr;
|
||||||
import com.semmle.ts.ast.TypeAliasDeclaration;
|
import com.semmle.ts.ast.TypeAliasDeclaration;
|
||||||
import com.semmle.ts.ast.TypeAssertion;
|
import com.semmle.ts.ast.TypeAssertion;
|
||||||
@@ -157,6 +158,8 @@ public interface Visitor<C, R> {
|
|||||||
|
|
||||||
public R visit(TemplateLiteral nd, C q);
|
public R visit(TemplateLiteral nd, C q);
|
||||||
|
|
||||||
|
public R visit(TemplateLiteralTypeExpr nd, C q);
|
||||||
|
|
||||||
public R visit(TaggedTemplateExpression nd, C q);
|
public R visit(TaggedTemplateExpression nd, C q);
|
||||||
|
|
||||||
public R visit(ArrowFunctionExpression nd, C q);
|
public R visit(ArrowFunctionExpression nd, C q);
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ import com.semmle.ts.ast.OptionalTypeExpr;
|
|||||||
import com.semmle.ts.ast.ParenthesizedTypeExpr;
|
import com.semmle.ts.ast.ParenthesizedTypeExpr;
|
||||||
import com.semmle.ts.ast.PredicateTypeExpr;
|
import com.semmle.ts.ast.PredicateTypeExpr;
|
||||||
import com.semmle.ts.ast.RestTypeExpr;
|
import com.semmle.ts.ast.RestTypeExpr;
|
||||||
|
import com.semmle.ts.ast.TemplateLiteralTypeExpr;
|
||||||
import com.semmle.ts.ast.TupleTypeExpr;
|
import com.semmle.ts.ast.TupleTypeExpr;
|
||||||
import com.semmle.ts.ast.TypeAliasDeclaration;
|
import com.semmle.ts.ast.TypeAliasDeclaration;
|
||||||
import com.semmle.ts.ast.TypeAssertion;
|
import com.semmle.ts.ast.TypeAssertion;
|
||||||
@@ -1270,6 +1271,13 @@ public class ASTExtractor {
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Label visit(TemplateLiteralTypeExpr nd, Context c) {
|
||||||
|
Label key = super.visit(nd, c);
|
||||||
|
visitAll(nd.getChildren(), key, IdContext.typeBind, 0);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Label visit(TemplateElement nd, Context c) {
|
public Label visit(TemplateElement nd, Context c) {
|
||||||
Label key = super.visit(nd, c);
|
Label key = super.visit(nd, c);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import com.semmle.js.ast.INode;
|
|||||||
import com.semmle.js.ast.Identifier;
|
import com.semmle.js.ast.Identifier;
|
||||||
import com.semmle.js.ast.Literal;
|
import com.semmle.js.ast.Literal;
|
||||||
import com.semmle.js.ast.MemberExpression;
|
import com.semmle.js.ast.MemberExpression;
|
||||||
|
import com.semmle.js.ast.TemplateElement;
|
||||||
import com.semmle.js.extractor.ASTExtractor.IdContext;
|
import com.semmle.js.extractor.ASTExtractor.IdContext;
|
||||||
import com.semmle.ts.ast.ArrayTypeExpr;
|
import com.semmle.ts.ast.ArrayTypeExpr;
|
||||||
import com.semmle.ts.ast.ConditionalTypeExpr;
|
import com.semmle.ts.ast.ConditionalTypeExpr;
|
||||||
@@ -22,6 +23,7 @@ import com.semmle.ts.ast.OptionalTypeExpr;
|
|||||||
import com.semmle.ts.ast.ParenthesizedTypeExpr;
|
import com.semmle.ts.ast.ParenthesizedTypeExpr;
|
||||||
import com.semmle.ts.ast.PredicateTypeExpr;
|
import com.semmle.ts.ast.PredicateTypeExpr;
|
||||||
import com.semmle.ts.ast.RestTypeExpr;
|
import com.semmle.ts.ast.RestTypeExpr;
|
||||||
|
import com.semmle.ts.ast.TemplateLiteralTypeExpr;
|
||||||
import com.semmle.ts.ast.TupleTypeExpr;
|
import com.semmle.ts.ast.TupleTypeExpr;
|
||||||
import com.semmle.ts.ast.TypeParameter;
|
import com.semmle.ts.ast.TypeParameter;
|
||||||
import com.semmle.ts.ast.TypeofTypeExpr;
|
import com.semmle.ts.ast.TypeofTypeExpr;
|
||||||
@@ -67,6 +69,7 @@ public class TypeExprKinds {
|
|||||||
private static final int restTypeExpr = 34;
|
private static final int restTypeExpr = 34;
|
||||||
private static final int bigintLiteralTypeExpr = 35;
|
private static final int bigintLiteralTypeExpr = 35;
|
||||||
private static final int readonlyTypeExpr = 36;
|
private static final int readonlyTypeExpr = 36;
|
||||||
|
private static final int templateLiteralTypeExpr = 37;
|
||||||
|
|
||||||
public static int getTypeExprKind(final INode type, final IdContext idcontext) {
|
public static int getTypeExprKind(final INode type, final IdContext idcontext) {
|
||||||
Integer kind =
|
Integer kind =
|
||||||
@@ -241,6 +244,16 @@ public class TypeExprKinds {
|
|||||||
public Integer visit(RestTypeExpr nd, Void c) {
|
public Integer visit(RestTypeExpr nd, Void c) {
|
||||||
return restTypeExpr;
|
return restTypeExpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer visit(TemplateLiteralTypeExpr nd, Void c) {
|
||||||
|
return templateLiteralTypeExpr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer visit(TemplateElement nd, Void c) {
|
||||||
|
return stringLiteralTypeExpr;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
null);
|
null);
|
||||||
if (kind == null)
|
if (kind == null)
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package com.semmle.ts.ast;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.semmle.js.ast.Expression;
|
||||||
|
import com.semmle.js.ast.INode;
|
||||||
|
import com.semmle.js.ast.Node;
|
||||||
|
import com.semmle.js.ast.SourceLocation;
|
||||||
|
import com.semmle.js.ast.TemplateElement;
|
||||||
|
import com.semmle.js.ast.TemplateLiteral;
|
||||||
|
import com.semmle.js.ast.Visitor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A template literal used in a type, such as in <code>type T = `Hello, ${name}!`</code>.
|
||||||
|
*/
|
||||||
|
public class TemplateLiteralTypeExpr extends TypeExpression {
|
||||||
|
private final List<ITypeExpression> expressions;
|
||||||
|
private final List<TemplateElement> quasis;
|
||||||
|
private final List<Node> children;
|
||||||
|
|
||||||
|
public TemplateLiteralTypeExpr(
|
||||||
|
SourceLocation loc, List<ITypeExpression> expressions, List<TemplateElement> quasis) {
|
||||||
|
super("TemplateLiteralTypeExpr", loc);
|
||||||
|
this.expressions = expressions;
|
||||||
|
this.quasis = quasis;
|
||||||
|
this.children = TemplateLiteral.<Node>mergeChildren(expressions, quasis);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||||
|
return v.visit(this, q);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The type expressions in this template. */
|
||||||
|
public List<ITypeExpression> getExpressions() {
|
||||||
|
return expressions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The template elements in this template. */
|
||||||
|
public List<TemplateElement> getQuasis() {
|
||||||
|
return quasis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** All type expressions and template elements in this template, in lexical order. */
|
||||||
|
public List<Node> getChildren() {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -145,6 +145,7 @@ import com.semmle.ts.ast.OptionalTypeExpr;
|
|||||||
import com.semmle.ts.ast.ParenthesizedTypeExpr;
|
import com.semmle.ts.ast.ParenthesizedTypeExpr;
|
||||||
import com.semmle.ts.ast.PredicateTypeExpr;
|
import com.semmle.ts.ast.PredicateTypeExpr;
|
||||||
import com.semmle.ts.ast.RestTypeExpr;
|
import com.semmle.ts.ast.RestTypeExpr;
|
||||||
|
import com.semmle.ts.ast.TemplateLiteralTypeExpr;
|
||||||
import com.semmle.ts.ast.TupleTypeExpr;
|
import com.semmle.ts.ast.TupleTypeExpr;
|
||||||
import com.semmle.ts.ast.TypeAliasDeclaration;
|
import com.semmle.ts.ast.TypeAliasDeclaration;
|
||||||
import com.semmle.ts.ast.TypeAssertion;
|
import com.semmle.ts.ast.TypeAssertion;
|
||||||
@@ -576,6 +577,8 @@ public class TypeScriptASTConverter {
|
|||||||
case "TemplateMiddle":
|
case "TemplateMiddle":
|
||||||
case "TemplateTail":
|
case "TemplateTail":
|
||||||
return convertTemplateElement(node, kind, loc);
|
return convertTemplateElement(node, kind, loc);
|
||||||
|
case "TemplateLiteralType":
|
||||||
|
return convertTemplateLiteralType(node, loc);
|
||||||
case "ThisKeyword":
|
case "ThisKeyword":
|
||||||
return convertThisKeyword(loc);
|
return convertThisKeyword(loc);
|
||||||
case "ThisType":
|
case "ThisType":
|
||||||
@@ -2152,6 +2155,19 @@ public class TypeScriptASTConverter {
|
|||||||
return new TemplateLiteral(loc, expressions, quasis);
|
return new TemplateLiteral(loc, expressions, quasis);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Node convertTemplateLiteralType(JsonObject node, SourceLocation loc) throws ParseError {
|
||||||
|
List<TemplateElement> quasis;
|
||||||
|
List<ITypeExpression> expressions = new ArrayList<>();
|
||||||
|
quasis = new ArrayList<>();
|
||||||
|
quasis.add(convertChild(node, "head"));
|
||||||
|
for (JsonElement elt : node.get("templateSpans").getAsJsonArray()) {
|
||||||
|
JsonObject templateSpan = (JsonObject) elt;
|
||||||
|
expressions.add(convertChildAsType(templateSpan, "type"));
|
||||||
|
quasis.add(convertChild(templateSpan, "literal"));
|
||||||
|
}
|
||||||
|
return new TemplateLiteralTypeExpr(loc, expressions, quasis);
|
||||||
|
}
|
||||||
|
|
||||||
private Node convertTemplateElement(JsonObject node, String kind, SourceLocation loc) {
|
private Node convertTemplateElement(JsonObject node, String kind, SourceLocation loc) {
|
||||||
boolean tail = "TemplateTail".equals(kind);
|
boolean tail = "TemplateTail".equals(kind);
|
||||||
if (loc.getSource().startsWith("`") || loc.getSource().startsWith("}")) {
|
if (loc.getSource().startsWith("`") || loc.getSource().startsWith("}")) {
|
||||||
|
|||||||
@@ -1213,6 +1213,29 @@ class InferTypeExpr extends @infer_typeexpr, TypeParameterized, TypeExpr {
|
|||||||
override string getAPrimaryQlClass() { result = "InferTypeExpr" }
|
override string getAPrimaryQlClass() { result = "InferTypeExpr" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A template literal used as a type.
|
||||||
|
*/
|
||||||
|
class TemplateLiteralTypeExpr extends @template_literal_typeexpr, TypeExpr {
|
||||||
|
/**
|
||||||
|
* Gets the `i`th element of this template literal, which may either
|
||||||
|
* be a type expression or a constant template element.
|
||||||
|
*/
|
||||||
|
ExprOrType getElement(int i) { result = getChild(i) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an element of this template literal.
|
||||||
|
*/
|
||||||
|
ExprOrType getAnElement() { result = getElement(_) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of elements of this template literal.
|
||||||
|
*/
|
||||||
|
int getNumElement() { result = count(getAnElement()) }
|
||||||
|
|
||||||
|
override string getAPrimaryQlClass() { result = "TemplateLiteralTypeExpr" }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A scope induced by a conditional type expression whose `extends` type
|
* A scope induced by a conditional type expression whose `extends` type
|
||||||
* contains `infer` types.
|
* contains `infer` types.
|
||||||
|
|||||||
@@ -584,6 +584,7 @@ case @typeexpr.kind of
|
|||||||
| 34 = @rest_typeexpr
|
| 34 = @rest_typeexpr
|
||||||
| 35 = @bigint_literal_typeexpr
|
| 35 = @bigint_literal_typeexpr
|
||||||
| 36 = @readonly_typeexpr
|
| 36 = @readonly_typeexpr
|
||||||
|
| 37 = @template_literal_typeexpr
|
||||||
;
|
;
|
||||||
|
|
||||||
@typeref = @typeaccess | @type_decl;
|
@typeref = @typeaccess | @type_decl;
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
// Based on snippets in https://devblogs.microsoft.com/typescript/announcing-typescript-4-1-beta/
|
||||||
|
|
||||||
|
type World = "world";
|
||||||
|
type Greeting = `hello ${World}`;
|
||||||
|
|
||||||
|
|
||||||
|
type Color = "red" | "blue";
|
||||||
|
type Quantity = "one" | "two";
|
||||||
|
type SeussFish = `${Quantity | Color} fish`;
|
||||||
|
|
||||||
|
|
||||||
|
type VerticalAlignment = "top" | "middle" | "bottom";
|
||||||
|
type HorizontalAlignment = "left" | "center" | "right";
|
||||||
|
declare function setAlignment(value: `${VerticalAlignment}-${HorizontalAlignment}`): void;
|
||||||
|
|
||||||
|
|
||||||
|
type PropEventSource<T> = {
|
||||||
|
on<K extends string & keyof T>(eventName: `${K}Changed`, callback: (newValue: T[K]) => void ): void;
|
||||||
|
};
|
||||||
|
|
||||||
|
declare function makeWatchedObject<T>(obj: T): T & PropEventSource<T>;
|
||||||
|
|
||||||
|
let person = makeWatchedObject({
|
||||||
|
firstName: "Homer",
|
||||||
|
age: 42,
|
||||||
|
location: "Springfield",
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Can no longer be parsed by TypeScript:
|
||||||
|
// type EnthusiasticGreeting<T extends string> = `${uppercase T}`
|
||||||
|
|
||||||
|
type HELLO = EnthusiasticGreeting<"hello">;
|
||||||
|
|
||||||
|
// Can no longer be parsed by TypeScript:
|
||||||
|
// type Getters<T> = {
|
||||||
|
// [K in keyof T as `get${capitalize K}`]: () => T[K]
|
||||||
|
// };
|
||||||
|
|
||||||
|
interface Person {
|
||||||
|
name: string;
|
||||||
|
age: number;
|
||||||
|
location: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type LazyPerson = Getters<Person>;
|
||||||
|
|
||||||
|
type RemoveKindField<T> = {
|
||||||
|
[K in keyof T as Exclude<K, "kind">]: T[K]
|
||||||
|
};
|
||||||
|
|
||||||
|
interface Circle {
|
||||||
|
kind: "circle";
|
||||||
|
radius: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
type KindlessCircle = RemoveKindField<Circle>;
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
| templateLiteralTypes.ts:4:17:4:32 | `hello ${World}` | 0 | templateLiteralTypes.ts:4:18:4:23 | hello |
|
||||||
|
| templateLiteralTypes.ts:4:17:4:32 | `hello ${World}` | 1 | templateLiteralTypes.ts:4:26:4:30 | World |
|
||||||
|
| templateLiteralTypes.ts:9:18:9:43 | `${Quan ... } fish` | 0 | templateLiteralTypes.ts:9:21:9:36 | Quantity \| Color |
|
||||||
|
| templateLiteralTypes.ts:9:18:9:43 | `${Quan ... } fish` | 1 | templateLiteralTypes.ts:9:38:9:42 | fish |
|
||||||
|
| templateLiteralTypes.ts:14:38:14:82 | `${Vert ... nment}` | 0 | templateLiteralTypes.ts:14:41:14:57 | VerticalAlignment |
|
||||||
|
| templateLiteralTypes.ts:14:38:14:82 | `${Vert ... nment}` | 1 | templateLiteralTypes.ts:14:59:14:59 | - |
|
||||||
|
| templateLiteralTypes.ts:14:38:14:82 | `${Vert ... nment}` | 2 | templateLiteralTypes.ts:14:62:14:80 | HorizontalAlignment |
|
||||||
|
| templateLiteralTypes.ts:18:47:18:59 | `${K}Changed` | 0 | templateLiteralTypes.ts:18:50:18:50 | K |
|
||||||
|
| templateLiteralTypes.ts:18:47:18:59 | `${K}Changed` | 1 | templateLiteralTypes.ts:18:52:18:58 | Changed |
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import javascript
|
||||||
|
|
||||||
|
query ExprOrType getElement(TemplateLiteralTypeExpr e, int i) {
|
||||||
|
result = e.getElement(i)
|
||||||
|
}
|
||||||
@@ -4,3 +4,7 @@ import SomeInterface from 'somewhere';
|
|||||||
class SomeClass implements SomeInterface {
|
class SomeClass implements SomeInterface {
|
||||||
}
|
}
|
||||||
new SomeClass();
|
new SomeClass();
|
||||||
|
|
||||||
|
import SomethingElse from 'somewhere'; // OK: SomethingElse is used in a type
|
||||||
|
|
||||||
|
type T = `Now for ${SomethingElse}`;
|
||||||
|
|||||||
Reference in New Issue
Block a user