typescript
Version:
TypeScript is a language for application scale JavaScript development
456 lines • 21.3 kB
JavaScript
// is.ts — Hand-written type guard functions
// Generated guards are in is.generated.ts
import { ModifierFlags } from "../../enums/modifierFlags.js";
import { NodeFlags } from "../../enums/nodeFlags.js";
import { OuterExpressionKinds } from "../../enums/outerExpressionKinds.js";
import { ScriptKind } from "../../enums/scriptKind.js";
import { SyntaxKind } from "../../enums/syntaxKind.js";
import { isBinaryExpression, isClassLikeDeclaration, isComputedPropertyName, isHeritageClause, isIdentifier, isJSDocAugmentsTag, isJSDocImplementsTag, isJSDocLink, isJSDocLinkCode, isJSDocLinkPlain, isJSDocNameReference, isLiteralExpression, isShorthandPropertyAssignment, } from "./is.generated.js";
import { hasExpression, hasInitializer, hasObjectAssignmentInitializer, } from "./utils.js";
export * from "./is.generated.js";
export function isTypeNode(node) {
return isTypeNodeKind(node.kind);
}
function isTypeNodeKind(kind) {
return kind >= SyntaxKind.FirstTypeNode && kind <= SyntaxKind.LastTypeNode
|| kind === SyntaxKind.AnyKeyword
|| kind === SyntaxKind.UnknownKeyword
|| kind === SyntaxKind.NumberKeyword
|| kind === SyntaxKind.BigIntKeyword
|| kind === SyntaxKind.ObjectKeyword
|| kind === SyntaxKind.BooleanKeyword
|| kind === SyntaxKind.StringKeyword
|| kind === SyntaxKind.SymbolKeyword
|| kind === SyntaxKind.VoidKeyword
|| kind === SyntaxKind.UndefinedKeyword
|| kind === SyntaxKind.NeverKeyword
|| kind === SyntaxKind.IntrinsicKeyword
|| kind === SyntaxKind.ExpressionWithTypeArguments
|| kind === SyntaxKind.JSDocAllType
|| kind === SyntaxKind.JSDocNullableType
|| kind === SyntaxKind.JSDocNonNullableType
|| kind === SyntaxKind.JSDocOptionalType
|| kind === SyntaxKind.JSDocVariadicType
|| kind === SyntaxKind.JSDocTypeExpression
|| kind === SyntaxKind.JSDocTypeLiteral
|| kind === SyntaxKind.JSDocSignature;
}
export function isStatement(node) {
const kind = node.kind;
return kind === SyntaxKind.VariableStatement || kind === SyntaxKind.EmptyStatement
|| kind === SyntaxKind.ExpressionStatement || kind === SyntaxKind.IfStatement
|| kind === SyntaxKind.DoStatement || kind === SyntaxKind.WhileStatement
|| kind === SyntaxKind.ForStatement || kind === SyntaxKind.ForInStatement
|| kind === SyntaxKind.ForOfStatement || kind === SyntaxKind.ContinueStatement
|| kind === SyntaxKind.BreakStatement || kind === SyntaxKind.ReturnStatement
|| kind === SyntaxKind.WithStatement || kind === SyntaxKind.SwitchStatement
|| kind === SyntaxKind.LabeledStatement || kind === SyntaxKind.ThrowStatement
|| kind === SyntaxKind.TryStatement || kind === SyntaxKind.DebuggerStatement
|| kind === SyntaxKind.InterfaceDeclaration || kind === SyntaxKind.TypeAliasDeclaration
|| kind === SyntaxKind.EnumDeclaration || kind === SyntaxKind.ModuleDeclaration
|| kind === SyntaxKind.ImportDeclaration || kind === SyntaxKind.ImportEqualsDeclaration
|| kind === SyntaxKind.ExportDeclaration || kind === SyntaxKind.ExportAssignment
|| kind === SyntaxKind.NamespaceExportDeclaration || kind === SyntaxKind.FunctionDeclaration
|| kind === SyntaxKind.ClassDeclaration || kind === SyntaxKind.MissingDeclaration
|| kind === SyntaxKind.NotEmittedStatement || kind === SyntaxKind.Block;
}
export function isExpression(node) {
const kind = node.kind;
return kind === SyntaxKind.ConditionalExpression || kind === SyntaxKind.YieldExpression
|| kind === SyntaxKind.ArrowFunction || kind === SyntaxKind.BinaryExpression
|| kind === SyntaxKind.SpreadElement || kind === SyntaxKind.AsExpression
|| kind === SyntaxKind.OmittedExpression
|| kind === SyntaxKind.SatisfiesExpression
|| kind === SyntaxKind.PrefixUnaryExpression || kind === SyntaxKind.PostfixUnaryExpression
|| kind === SyntaxKind.DeleteExpression || kind === SyntaxKind.TypeOfExpression
|| kind === SyntaxKind.VoidExpression || kind === SyntaxKind.AwaitExpression
|| kind === SyntaxKind.TypeAssertionExpression
|| kind === SyntaxKind.CallExpression || kind === SyntaxKind.NewExpression
|| kind === SyntaxKind.TaggedTemplateExpression || kind === SyntaxKind.NonNullExpression
|| kind === SyntaxKind.MetaProperty || kind === SyntaxKind.JsxExpression
|| kind === SyntaxKind.PropertyAccessExpression || kind === SyntaxKind.ElementAccessExpression
|| kind === SyntaxKind.FunctionExpression || kind === SyntaxKind.ClassExpression
|| kind === SyntaxKind.ParenthesizedExpression || kind === SyntaxKind.ArrayLiteralExpression
|| kind === SyntaxKind.ObjectLiteralExpression || kind === SyntaxKind.TemplateExpression
|| kind === SyntaxKind.Identifier
|| kind === SyntaxKind.PrivateIdentifier
|| kind === SyntaxKind.NumericLiteral || kind === SyntaxKind.BigIntLiteral
|| kind === SyntaxKind.StringLiteral || kind === SyntaxKind.RegularExpressionLiteral
|| kind === SyntaxKind.NoSubstitutionTemplateLiteral || kind === SyntaxKind.JsxElement
|| kind === SyntaxKind.JsxSelfClosingElement || kind === SyntaxKind.JsxFragment
|| kind === SyntaxKind.NullKeyword || kind === SyntaxKind.TrueKeyword
|| kind === SyntaxKind.FalseKeyword || kind === SyntaxKind.ThisKeyword
|| kind === SyntaxKind.SuperKeyword || kind === SyntaxKind.ImportKeyword
|| kind === SyntaxKind.ExpressionWithTypeArguments;
}
export function isValidTypeOnlyAliasUseSite(useSite) {
return !!(useSite.flags & NodeFlags.Ambient)
|| isInJSDoc(useSite)
|| isPartOfTypeQuery(useSite)
|| isIdentifierInNonEmittingHeritageClause(useSite)
|| isPartOfPossiblyValidTypeOrAbstractComputedPropertyName(useSite)
|| !(isExpressionNode(useSite) || isShorthandPropertyNameUseSite(useSite));
}
function isInJSDoc(node) {
return !!(node.flags & NodeFlags.JSDoc);
}
function isPartOfTypeQuery(node) {
while (node.kind === SyntaxKind.QualifiedName || node.kind === SyntaxKind.Identifier) {
node = node.parent;
}
return node.kind === SyntaxKind.TypeQuery;
}
function isIdentifierInNonEmittingHeritageClause(node) {
if (!isIdentifier(node))
return false;
const heritageClause = findAncestor(node.parent, parent => {
switch (parent.kind) {
case SyntaxKind.HeritageClause:
return true;
case SyntaxKind.PropertyAccessExpression:
case SyntaxKind.ExpressionWithTypeArguments:
return false;
default:
return "quit";
}
});
return heritageClause !== undefined &&
isHeritageClause(heritageClause) &&
(heritageClause.token === SyntaxKind.ImplementsKeyword || heritageClause.parent.kind === SyntaxKind.InterfaceDeclaration);
}
function isPartOfPossiblyValidTypeOrAbstractComputedPropertyName(node) {
while (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PropertyAccessExpression) {
node = node.parent;
}
if (!isComputedPropertyName(node)) {
return false;
}
if (hasModifierFlags(node.parent) && node.parent.modifierFlags & ModifierFlags.Abstract) {
return true;
}
const containerKind = node.parent.parent.kind;
return containerKind === SyntaxKind.InterfaceDeclaration || containerKind === SyntaxKind.TypeLiteral;
}
function isShorthandPropertyNameUseSite(useSite) {
return isIdentifier(useSite) && isShorthandPropertyAssignment(useSite.parent) && useSite.parent.name === useSite;
}
function findAncestor(node, callback) {
while (node) {
const result = callback(node);
if (result === "quit") {
return undefined;
}
if (result) {
return node;
}
node = node.parent;
}
}
function hasModifierFlags(node) {
return "modifierFlags" in node;
}
function isExpressionNode(node) {
switch (node.kind) {
case SyntaxKind.SuperKeyword:
case SyntaxKind.NullKeyword:
case SyntaxKind.TrueKeyword:
case SyntaxKind.FalseKeyword:
case SyntaxKind.RegularExpressionLiteral:
case SyntaxKind.ArrayLiteralExpression:
case SyntaxKind.ObjectLiteralExpression:
case SyntaxKind.PropertyAccessExpression:
case SyntaxKind.ElementAccessExpression:
case SyntaxKind.CallExpression:
case SyntaxKind.NewExpression:
case SyntaxKind.TaggedTemplateExpression:
case SyntaxKind.AsExpression:
case SyntaxKind.TypeAssertionExpression:
case SyntaxKind.SatisfiesExpression:
case SyntaxKind.NonNullExpression:
case SyntaxKind.ParenthesizedExpression:
case SyntaxKind.FunctionExpression:
case SyntaxKind.ClassExpression:
case SyntaxKind.ArrowFunction:
case SyntaxKind.VoidExpression:
case SyntaxKind.DeleteExpression:
case SyntaxKind.TypeOfExpression:
case SyntaxKind.PrefixUnaryExpression:
case SyntaxKind.PostfixUnaryExpression:
case SyntaxKind.BinaryExpression:
case SyntaxKind.ConditionalExpression:
case SyntaxKind.SpreadElement:
case SyntaxKind.TemplateExpression:
case SyntaxKind.OmittedExpression:
case SyntaxKind.JsxElement:
case SyntaxKind.JsxSelfClosingElement:
case SyntaxKind.JsxFragment:
case SyntaxKind.YieldExpression:
case SyntaxKind.AwaitExpression:
return true;
case SyntaxKind.MetaProperty:
return !isImportCall(node.parent) || node.parent.expression !== node;
case SyntaxKind.ExpressionWithTypeArguments:
return !isHeritageClause(node.parent);
case SyntaxKind.QualifiedName:
while (node.parent.kind === SyntaxKind.QualifiedName) {
node = node.parent;
}
return node.parent.kind === SyntaxKind.TypeQuery || isInJSDocNameReference(node) || isJSXTagName(node);
case SyntaxKind.PrivateIdentifier:
return isBinaryExpression(node.parent) && node.parent.left === node && node.parent.operatorToken.kind === SyntaxKind.InKeyword;
case SyntaxKind.Identifier:
if (node.parent.kind === SyntaxKind.TypeQuery || isInJSDocNameReference(node) || isJSXTagName(node)) {
return true;
}
// falls through
case SyntaxKind.NumericLiteral:
case SyntaxKind.BigIntLiteral:
case SyntaxKind.StringLiteral:
case SyntaxKind.NoSubstitutionTemplateLiteral:
case SyntaxKind.ThisKeyword:
return isInExpressionContext(node);
default:
return false;
}
}
function isImportCall(node) {
if (node.kind !== SyntaxKind.CallExpression || !hasExpression(node) || !node.expression) {
return false;
}
return node.expression.kind === SyntaxKind.MetaProperty
&& node.expression.keywordToken === SyntaxKind.ImportKeyword;
}
function isJSDocLinkLike(node) {
return isJSDocLink(node) || isJSDocLinkCode(node) || isJSDocLinkPlain(node);
}
function isInJSDocNameReference(node) {
return isJSDocLinkLike(node.parent) || isJSDocNameReference(node.parent);
}
function isInExpressionContext(node) {
const parent = node.parent;
switch (parent.kind) {
case SyntaxKind.VariableDeclaration:
case SyntaxKind.Parameter:
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
case SyntaxKind.EnumMember:
case SyntaxKind.PropertyAssignment:
case SyntaxKind.BindingElement:
return hasInitializer(parent) && parent.initializer === node;
case SyntaxKind.ExpressionStatement:
case SyntaxKind.IfStatement:
case SyntaxKind.DoStatement:
case SyntaxKind.WhileStatement:
case SyntaxKind.ReturnStatement:
case SyntaxKind.WithStatement:
case SyntaxKind.SwitchStatement:
case SyntaxKind.CaseClause:
case SyntaxKind.DefaultClause:
case SyntaxKind.ThrowStatement:
return hasExpression(parent) && parent.expression === node;
case SyntaxKind.ForStatement:
return isForStatementExpression(node, parent);
case SyntaxKind.ForInStatement:
case SyntaxKind.ForOfStatement:
return isForInOrOfStatementExpression(node, parent);
case SyntaxKind.TypeAssertionExpression:
case SyntaxKind.AsExpression:
return hasExpression(parent) && parent.expression === node;
case SyntaxKind.TemplateSpan:
return hasExpression(parent) && parent.expression === node;
case SyntaxKind.ComputedPropertyName:
return parent.expression === node;
case SyntaxKind.Decorator:
case SyntaxKind.JsxExpression:
case SyntaxKind.JsxSpreadAttribute:
case SyntaxKind.SpreadAssignment:
return true;
case SyntaxKind.ExpressionWithTypeArguments:
return parent.expression === node && !isPartOfTypeExpressionWithTypeArguments(parent);
case SyntaxKind.ShorthandPropertyAssignment:
return hasObjectAssignmentInitializer(parent) && parent.objectAssignmentInitializer === node;
case SyntaxKind.SatisfiesExpression:
return hasExpression(parent) && parent.expression === node;
default:
return isExpressionNode(parent);
}
}
function isPartOfTypeExpressionWithTypeArguments(node) {
const parent = node.parent;
return isHeritageClause(parent) && (!isClassLikeDeclaration(parent.parent) || parent.token === SyntaxKind.ImplementsKeyword) ||
isJSDocImplementsTag(parent) ||
isJSDocAugmentsTag(parent);
}
function isForStatementExpression(node, parent) {
return parent.initializer === node && parent.initializer.kind !== SyntaxKind.VariableDeclarationList ||
parent.condition === node ||
parent.incrementor === node;
}
function isForInOrOfStatementExpression(node, parent) {
return parent.initializer === node && parent.initializer.kind !== SyntaxKind.VariableDeclarationList ||
parent.expression === node;
}
function isJSXTagName(node) {
const parent = node.parent;
switch (parent.kind) {
case SyntaxKind.JsxOpeningElement:
case SyntaxKind.JsxSelfClosingElement:
case SyntaxKind.JsxClosingElement:
return hasTagName(parent) && parent.tagName === node;
default:
return false;
}
}
function hasTagName(node) {
return "tagName" in node;
}
export function isBlockOrExpression(node) {
return node.kind === SyntaxKind.Block || isExpression(node);
}
export function isLeftHandSideExpression(node) {
return isLeftHandSideExpressionKind(skipPartiallyEmittedExpressions(node).kind);
}
export function skipPartiallyEmittedExpressions(node) {
return skipOuterExpressions(node, OuterExpressionKinds.PartiallyEmittedExpressions);
}
function isLeftHandSideExpressionKind(kind) {
switch (kind) {
case SyntaxKind.PropertyAccessExpression:
case SyntaxKind.ElementAccessExpression:
case SyntaxKind.NewExpression:
case SyntaxKind.CallExpression:
case SyntaxKind.JsxElement:
case SyntaxKind.JsxSelfClosingElement:
case SyntaxKind.JsxFragment:
case SyntaxKind.TaggedTemplateExpression:
case SyntaxKind.ArrayLiteralExpression:
case SyntaxKind.ParenthesizedExpression:
case SyntaxKind.ObjectLiteralExpression:
case SyntaxKind.ClassExpression:
case SyntaxKind.FunctionExpression:
case SyntaxKind.Identifier:
case SyntaxKind.PrivateIdentifier: // technically this is only an Expression if it's in a `#field in expr` BinaryExpression
case SyntaxKind.RegularExpressionLiteral:
case SyntaxKind.NumericLiteral:
case SyntaxKind.BigIntLiteral:
case SyntaxKind.StringLiteral:
case SyntaxKind.NoSubstitutionTemplateLiteral:
case SyntaxKind.TemplateExpression:
case SyntaxKind.FalseKeyword:
case SyntaxKind.NullKeyword:
case SyntaxKind.ThisKeyword:
case SyntaxKind.TrueKeyword:
case SyntaxKind.SuperKeyword:
case SyntaxKind.NonNullExpression:
case SyntaxKind.ExpressionWithTypeArguments:
case SyntaxKind.MetaProperty:
case SyntaxKind.ImportKeyword: // technically this is only an Expression if it's in a CallExpression
case SyntaxKind.MissingDeclaration:
return true;
default:
return false;
}
}
export function isUnaryExpression(node) {
return isUnaryExpressionKind(skipPartiallyEmittedExpressions(node).kind);
}
function isUnaryExpressionKind(kind) {
switch (kind) {
case SyntaxKind.PrefixUnaryExpression:
case SyntaxKind.PostfixUnaryExpression:
case SyntaxKind.DeleteExpression:
case SyntaxKind.TypeOfExpression:
case SyntaxKind.VoidExpression:
case SyntaxKind.AwaitExpression:
case SyntaxKind.TypeAssertionExpression:
return true;
default:
return isLeftHandSideExpressionKind(kind);
}
}
/** @internal */
export function isOuterExpression(node, kinds = OuterExpressionKinds.All) {
switch (node.kind) {
case SyntaxKind.ParenthesizedExpression:
if (kinds & OuterExpressionKinds.ExcludeJSDocTypeAssertion && isJSDocTypeAssertion(node)) {
return false;
}
return (kinds & OuterExpressionKinds.Parentheses) !== 0;
case SyntaxKind.TypeAssertionExpression:
case SyntaxKind.AsExpression:
return (kinds & OuterExpressionKinds.TypeAssertions) !== 0;
case SyntaxKind.SatisfiesExpression:
return (kinds & (OuterExpressionKinds.ExpressionsWithTypeArguments | OuterExpressionKinds.Satisfies)) !== 0;
case SyntaxKind.ExpressionWithTypeArguments:
return (kinds & OuterExpressionKinds.ExpressionsWithTypeArguments) !== 0;
case SyntaxKind.NonNullExpression:
return (kinds & OuterExpressionKinds.NonNullAssertions) !== 0;
case SyntaxKind.PartiallyEmittedExpression:
return (kinds & OuterExpressionKinds.PartiallyEmittedExpressions) !== 0;
}
return false;
}
/** @internal */
export function skipOuterExpressions(node, kinds = OuterExpressionKinds.All) {
while (isOuterExpression(node, kinds)) {
node = node.expression;
}
return node;
}
function isJSDocTypeAssertion(node) {
const sourceFile = node.getSourceFile();
if (sourceFile.scriptKind !== ScriptKind.JS && sourceFile.scriptKind !== ScriptKind.JSX) {
return false;
}
const expression = node.expression;
if (expression.kind !== SyntaxKind.AsExpression) {
return false;
}
const asExpression = expression;
return !!asExpression.type
&& (asExpression.type.flags & NodeFlags.Reparsed) !== 0;
}
export function isBindingPattern(node) {
return node.kind === SyntaxKind.ObjectBindingPattern || node.kind === SyntaxKind.ArrayBindingPattern;
}
export function isConciseBody(node) {
return node.kind === SyntaxKind.Block || isExpression(node);
}
export function isForInitializer(node) {
return node.kind === SyntaxKind.VariableDeclarationList || isExpression(node);
}
export function isQuestionOrExclamationToken(node) {
return node.kind === SyntaxKind.QuestionToken || node.kind === SyntaxKind.ExclamationToken;
}
export function isIdentifierOrThisTypeNode(node) {
return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.ThisType;
}
export function isReadonlyKeywordOrPlusOrMinusToken(node) {
return node.kind === SyntaxKind.ReadonlyKeyword || node.kind === SyntaxKind.PlusToken || node.kind === SyntaxKind.MinusToken;
}
export function isQuestionOrPlusOrMinusToken(node) {
return node.kind === SyntaxKind.QuestionToken || node.kind === SyntaxKind.PlusToken || node.kind === SyntaxKind.MinusToken;
}
export function isTemplateMiddleOrTemplateTail(node) {
return node.kind === SyntaxKind.TemplateMiddle || node.kind === SyntaxKind.TemplateTail;
}
export function isLiteralTypeLiteral(node) {
const kind = node.kind;
return kind === SyntaxKind.NullKeyword || kind === SyntaxKind.TrueKeyword
|| kind === SyntaxKind.FalseKeyword || kind === SyntaxKind.PrefixUnaryExpression
|| isLiteralExpression(node);
}
export function isIdentifierOrJSDocNamespaceDeclaration(node) {
return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.ModuleDeclaration;
}
export function isJSDocTypeExpressionOrJSDocTypeLiteral(node) {
return node.kind === SyntaxKind.JSDocTypeExpression || node.kind === SyntaxKind.JSDocTypeLiteral;
}
export function isJsxTagNameExpression(node) {
const kind = node.kind;
return kind === SyntaxKind.ThisKeyword
|| kind === SyntaxKind.Identifier
|| kind === SyntaxKind.PropertyAccessExpression
|| kind === SyntaxKind.JsxNamespacedName;
}
//# sourceMappingURL=is.js.map