विचाराधीन वांछित जानकारी को लॉग आउट करने के लिए टाइपस्क्रिप्ट में कोई अंतर्निहित तंत्र नहीं है। हालांकि, यदि आप आंतरिक कार्य को समझने में रुचि रखते हैं, तो यहां स्रोत कोड में वह जगह है जहां वास्तव में सशर्त प्रकारों का समाधान होता है।
इन स्थानों पर एक नज़र डालें checker.ts
।
ln: 13258 instantiateTypeWorker()
ln: 12303 getConditionalType()
ln: 12385 getTypeFromConditionalTypeNode()
ln: 12,772getTypeFromTypeNode()
संलग्न एक आधा किया हुआ टाइपस्क्रिप्ट प्लगइन है जिसे मैंने लापरवाही से एक साथ रखा है। यह कच्चे डेटा संरचना को लॉग आउट करता है ConditionalType
। इस संरचना को समझने के लिए, check.ts ln: 4634 देखें।
इस प्लगइन का यूएक्स भयानक है, लेकिन यह संरचना आपको बताती है कि टाइपस्क्रिप्ट एक सशर्त प्रकार का अंतिम मूल्य कैसे तय करती है।
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;
इस प्लगइन को चलाने के लिए कुछ कष्टप्रद विस्तृत निर्देश:
mkdir my-ts-plugin && cd my-ts-plugin
touch package.json
और लिखा { "name": "my-ts-plugin", "main": "index.js" }
yarn add typescript fast-safe-stringify
- इस स्निपेट को कॉपी-पेस्ट करें
index.ts
, इसे संकलित करने के लिए tsc का उपयोग करेंindex.js
yarn link
- अब
cd
अपने खुद के टीएस परियोजना के लिए, भागोyarn link my-ts-plugin
{ "compilerOptions": { "plugins": [{ "name": "my-ts-plugin" }] } }
अपने को जोड़ेंtsconfig.json
(.vscode/settings.json)
इस पंक्ति को सेट करने के लिए कार्यस्थान में जोड़ें :{ "typescript.tsdk": "<PATH_TO_YOUR_TS_PROJECT>/node_modules/typescript/lib" }
- vscode कमांड पैलेट खोलें और चलाएं:
TypeScript: Select TypeScript Version... -> Use Workspace Version
TypeScript: Restart TS Server
TypeScript: Open TS Server Log
- आपको प्लगइन लॉग आउट देखने में सक्षम होना चाहिए
"PLUGIN UP AND RUNNING"
, अब कुछ सशर्त प्रकार के नोड के लिए एक ts कोड फ़ाइल और माउस होवर खोलें, आपको लॉग फ़ाइल में जोड़ा गया एक loooooong json डेटा स्ट्रक्चर देखना चाहिए।