В таких случаях полезно изучить структуру AST вашего кода и обращаться к ней при создании решения. Вы можете анализировать AST с помощью TypeScript AST Viewer.
Вот как выглядит ваш код
Здесь вы можете видеть, что ваш MethodDeclaration
имеет свойство typeParameters
, которое является массивом TypeParameter
. Он также имеет parameters
, который является массивом Parameter
.
. Вам нужно заменить любой TypeReference
, который встречается в любом потомке узлов в parameters
, который указывает на O
с соответствующим свойством TypeParameter
O
constraint
.
Для этого есть несколько маршрутов. Самый простой и наиболее широко документированный подход - это использование трансформатора.
Пример кода
Следующий пример будет применяться ко всем методам. Он ищет TypeReference
узлов в любом месте parameters
NodeArray
и проверяет, является ли это ссылкой на один из TypeParameter
s метода. Если это так, он заменит эту ссылку своим ограничением.
Это немного шире, чем ваш вопрос, но я предположил, что ваше реальное приложение может быть ближе к этому. Если нет, то вы сможете легко изменить его, чтобы указать целевые c методы или имена параметров.
Надеемся, это поможет вам указать правильное направление
Попробуйте код в StackBlitz: https://stackblitz.com/edit/typescript-transformer-example?file=index.ts
import * as ts from 'typescript'
import { Node, SourceFile } from 'typescript'
/* ****************************************************************************************************************** *
* Code to transform
* ****************************************************************************************************************** */
const cls = `
class Sample {
sn<O extends string>(input:{ one: O, twO : {k : O} ,three:O[] }) {
}
}
`;
/* ****************************************************************************************************************** *
* Transformer
* ****************************************************************************************************************** */
const transformer = (ctx: ts.TransformationContext) => (sourceFile: SourceFile): SourceFile => {
function paramVisitor(baseMethod: ts.MethodDeclaration) {
return (node: Node): Node => {
if (ts.isTypeReferenceNode(node)) {
const typeParam = baseMethod.typeParameters.find(t => t.name.escapedText === (node.typeName as ts.Identifier).escapedText);
if (typeParam) return typeParam.constraint;
}
return ts.visitEachChild(node, paramVisitor(baseMethod), ctx);
};
}
const visit = (node: Node): Node => {
if (ts.isMethodDeclaration(node))
return ts.updateMethod(
node,
node.decorators,
node.modifiers,
node.asteriskToken,
node.name,
node.questionToken,
node.typeParameters,
ts.visitNodes(node.parameters, paramVisitor(node)),
node.type,
node.body
);
return ts.visitEachChild(node, visit, ctx);
};
return ts.visitNode(sourceFile, visit);
};
/* ****************************************************************************************************************** *
* Demonstration
* ****************************************************************************************************************** */
const s = ts.createSourceFile('example.ts', cls, ts.ScriptTarget.ES5);
const { transformed } = ts.transform(s, [ transformer ]);
console.log(ts.createPrinter().printFile(transformed.find(f => f.fileName === 'example.ts')));
Рекомендуемое чтение:
Как написать преобразование TypeScript (плагин)
Создание TypeScript Transformer
Рекомендуемые инструменты:
ts-query - Для более хирургического подхода
ts-morph - может помочь упростить работу API компилятора.
ts-patch - если вам нужно применять преобразователи во время компиляции ts c
PS
В будущем добавьте тег typescript-compiler-api к своим сообщениям. На эти типы вопросов гораздо больше шансов получить ответ с помощью этого тега.