No hay ningún mecanismo incorporado en mecanografiado para cerrar la información deseada en cuestión. Sin embargo, si está interesado en comprender el trabajo interno, este es el lugar en el código fuente donde ocurre la resolución real de los tipos condicionales.
Echa un vistazo a estos lugares en checker.ts
.
ln: 13258 instantiateTypeWorker()
ln: 12303 getConditionalType()
ln: 12385 getTypeFromConditionalTypeNode()
ln: 12772getTypeFromTypeNode()
Adjunto hay un plugin mecanografiado a medio hacer que armé descuidadamente. Se desconecta la estructura de datos en bruto de a ConditionalType
. Para entender esta estructura, verifique types.ts ln: 4634.
La experiencia de usuario de este complemento es terrible, pero esa estructura le dice cómo el mecanografiado decide el valor final de un tipo condicional.
import stringify from "fast-safe-stringify";
function init(modules: {
typescript: typeof import("typescript/lib/tsserverlibrary");
}) {
const ts = modules.typescript;
// #region utils
function replacer(name, val) {
if (name === "checker" || name === "parent") {
return undefined;
}
return val;
}
function getContainingObjectLiteralElement(node) {
var element = getContainingObjectLiteralElementWorker(node);
return element &&
(ts.isObjectLiteralExpression(element.parent) ||
ts.isJsxAttributes(element.parent))
? element
: undefined;
}
ts.getContainingObjectLiteralElement = getContainingObjectLiteralElement;
function getContainingObjectLiteralElementWorker(node) {
switch (node.kind) {
case 10 /* StringLiteral */:
case 14 /* NoSubstitutionTemplateLiteral */:
case 8 /* NumericLiteral */:
if (node.parent.kind === 153 /* ComputedPropertyName */) {
return ts.isObjectLiteralElement(node.parent.parent)
? node.parent.parent
: undefined;
}
// falls through
case 75 /* Identifier */:
return ts.isObjectLiteralElement(node.parent) &&
(node.parent.parent.kind === 192 /* ObjectLiteralExpression */ ||
node.parent.parent.kind === 272) /* JsxAttributes */ &&
node.parent.name === node
? node.parent
: undefined;
}
return undefined;
}
function getPropertySymbolsFromContextualType(
node,
checker,
contextualType,
unionSymbolOk
) {
var name = ts.getNameFromPropertyName(node.name);
if (!name) return ts.emptyArray;
if (!contextualType.isUnion()) {
var symbol = contextualType.getProperty(name);
return symbol ? [symbol] : ts.emptyArray;
}
var discriminatedPropertySymbols = ts.mapDefined(
contextualType.types,
function(t) {
return ts.isObjectLiteralExpression(node.parent) &&
checker.isTypeInvalidDueToUnionDiscriminant(t, node.parent)
? undefined
: t.getProperty(name);
}
);
if (
unionSymbolOk &&
(discriminatedPropertySymbols.length === 0 ||
discriminatedPropertySymbols.length === contextualType.types.length)
) {
var symbol = contextualType.getProperty(name);
if (symbol) return [symbol];
}
if (discriminatedPropertySymbols.length === 0) {
// Bad discriminant -- do again without discriminating
return ts.mapDefined(contextualType.types, function(t) {
return t.getProperty(name);
});
}
return discriminatedPropertySymbols;
}
ts.getPropertySymbolsFromContextualType = getPropertySymbolsFromContextualType;
function getNodeForQuickInfo(node) {
if (ts.isNewExpression(node.parent) && node.pos === node.parent.pos) {
return node.parent.expression;
}
return node;
}
// #endregion
/**
* plugin code starts here
*/
function create(info: ts.server.PluginCreateInfo) {
const log = (s: any) => {
const prefix =
">>>>>>>> [TYPESCRIPT-FOOBAR-PLUGIN] <<<<<<<< \n";
const suffix = "\n<<<<<<<<<<<";
if (typeof s === "object") {
s = stringify(s, null, 2);
}
info.project.projectService.logger.info(prefix + String(s) + suffix);
};
// Diagnostic logging
log("PLUGIN UP AND RUNNING");
// Set up decorator
const proxy: ts.LanguageService = Object.create(null);
for (let k of Object.keys(info.languageService) as Array<
keyof ts.LanguageService
>) {
const x = info.languageService[k];
proxy[k] = (...args: Array<{}>) => x.apply(info.languageService, args);
}
proxy.getQuickInfoAtPosition = (filename, position) => {
var program = ts.createProgram(
[filename],
info.project.getCompilerOptions()
);
var sourceFiles = program.getSourceFiles();
var sourceFile = sourceFiles[sourceFiles.length - 1];
var checker = program.getDiagnosticsProducingTypeChecker();
var node = ts.getTouchingPropertyName(sourceFile, position);
var nodeForQuickInfo = getNodeForQuickInfo(node);
var nodeType = checker.getTypeAtLocation(nodeForQuickInfo);
let res;
if (nodeType.flags & ts.TypeFlags.Conditional) {
log(stringify(nodeType, replacer, 2));
}
if (!res)
res = info.languageService.getQuickInfoAtPosition(filename, position);
return res;
};
return proxy;
}
return { create };
}
export = init;
Algunas instrucciones molestas y detalladas para ejecutar este complemento:
mkdir my-ts-plugin && cd my-ts-plugin
touch package.json
y escribe { "name": "my-ts-plugin", "main": "index.js" }
yarn add typescript fast-safe-stringify
- copia y pega este fragmento en
index.ts
, usa tsc para compilarloindex.js
yarn link
- ahora
cd
al directorio de tu propio proyecto ts, ejecutayarn link my-ts-plugin
- agregar
{ "compilerOptions": { "plugins": [{ "name": "my-ts-plugin" }] } }
a sutsconfig.json
- agregar al espacio de trabajo configurando
(.vscode/settings.json)
esta línea:{ "typescript.tsdk": "<PATH_TO_YOUR_TS_PROJECT>/node_modules/typescript/lib" }
- Abra la paleta de comandos vscode y ejecute:
TypeScript: Select TypeScript Version... -> Use Workspace Version
TypeScript: Restart TS Server
TypeScript: Open TS Server Log
- debería poder ver el cierre de sesión del complemento
"PLUGIN UP AND RUNNING"
, ahora abra un archivo de código ts y desplace el mouse hacia algún nodo de tipo condicional, debería ver una estructura de datos json muuuuuuuuuuuu larga agregada al archivo de registro.