Это невозможно со стандартным компилятором TS. Типы TypeScript полностью удаляются во время выполнения, поэтому эта информация больше недоступна.
Однако, если вы скомпилируете свой источник с помощью специального скрипта, а не просто с помощью tsc
, это станет возможным.
Чтобы упростить код, я использовал здесь ts-simple-ast .
Это хорошая идея? Нет ... но это было весело.
import { Project, VariableDeclaration, Type, WriterFunction } from 'ts-simple-ast' // ^21.0.0
const project = new Project()
project.addExistingSourceFiles('src/**/*.ts')
// Custom functionality
// Look for variables that have a doc comment with `@autoInit`
// Get their type, and assign values to https://stackoverflow.com/q/54260406/7186598
for (const sourceFile of project.getSourceFiles()) {
// TODO: Class properties, object literal properties, etc.?
const declarations = sourceFile.getVariableDeclarations()
for (const declaration of declarations.filter(hasAutoInitTag)) {
if (declaration.hasInitializer()) {
console.warn(`'${declaration.getName()}' has an initializer and @autoInit tag. Skipping.`)
continue
}
const type = declaration.getType()
const writer = createWriterForType(declaration.getName(), type);
const parentStatement = declaration.getParent().getParent()
const index = sourceFile.getStatements().findIndex(statement => statement === parentStatement)
// Insert after the variable declaration
sourceFile.insertStatements(index + 1, writer);
}
console.log(sourceFile.getFullText())
// Uncomment once you have verified it does what you want.
// sourceFile.saveSync()
}
// There's almost certainly a better way to do this.
function hasAutoInitTag(declaration: VariableDeclaration) {
// Comments are attached to a VariableDeclarationList which contains VariableDeclarations, so
// get the parent.
const comments = declaration.getParent().getLeadingCommentRanges().map(range => range.getText())
return comments.some(comment => comment.includes('@autoInit'))
}
function createWriterForType(name: string, type: Type): WriterFunction {
return writer => {
function writeTypeInitializer(nameStack: string[], type: Type) {
if (type.isString()) {
// Some logic for non-standard names is probably a good idea here.
// this won't handle names like '()\'"'
writer.writeLine(`${nameStack.join('.')} = '${nameStack.slice(1).join('_')}'`)
} else if (type.isObject()) {
writer.writeLine(`${nameStack.join('.')} = {}`)
for (const prop of type.getProperties()) {
const node = prop.getValueDeclarationOrThrow()
writeTypeInitializer(nameStack.concat(prop.getName()), prop.getTypeAtLocation(node))
}
} else {
console.warn('Unknown type', nameStack, type.getText())
}
}
writeTypeInitializer([name], type)
}
}
Теперь, менее захватывающее решение.
Вместо описания вашего объекта с помощью интерфейса, вы можете сгенерировать интерфейс из объекта. Затем ключи будут доступны для доступа с помощью функции autoInit
, которая может генерировать нужные вам строки. Демонстрация игровой площадки
// Exactly the same as the original interface
type MyObjects = typeof myObjects
let myObjects = {
Troll: {
strength: '',
dexterity: '',
wisdom: ''
},
Child: {
health: '',
wellness: ''
},
Kitten: {
sneakFactor: '',
color: ''
}
};
autoInit(myObjects)
console.log(myObjects)
type AutoInitable = { [k: string]: AutoInitable } | string
function autoInit(obj: { [k: string]: AutoInitable }, nameStack: string[] = []) {
for (const key of Object.keys(obj)) {
const val = obj[key]
if (typeof val === 'string') {
obj[key] = [...nameStack, key].join('_')
} else {
autoInit(val, nameStack.concat(key))
}
}
}
Вопрос adiga
связан еще с одним вариантом, который, вероятно, лучше, так как он более общий. Вы можете получить доступ к подтипам с помощью MyObjects['Troll']
, но я уверен, что вы не сможете сделать это автоматически на любой глубине, как вы можете с помощью двух вышеупомянутых опций.
Если Вы хотите произвести анимацию, Вы лучше используете специализированные инструменты для нее (как mplayer).
Используйте gnuplot, чтобы подготовить все исходные изображения (сначала один с одной строкой, напечатанной, второй - с двумя строками, и т.д.), затем использовать mplayer или преобразовать (из imagemagic) для создания avi, или анимировал GIF из исходных файлов.
Можно использовать следующий отрывок оболочки для создания частичных копий входного файла, каждого с растущим числом строк.
file="your input file.dat"
lines=$(wc -l $file)
i=1
while [ $i -le $lines ] ; do
head -${i} ${file} > ${file%.dat}-${i}lines.dat
done
Данный somefile.dat это произведет файлы "somefile-1lines.dat", "somefile-2lines.dat" и т.д. Затем можно использовать:
for f in *lines.dat ; do
gnuplot ... $f
done
вывести их всех на печать в последовательности.
Если мое предположение является неправильным и все, что Вы действительно хотите, эта пауза, то можно попытаться настроить вещи так, чтобы gnuplot получил данные из stdin и затем использовал этот scipt (назовите приостановленным-input.sh) для передачи по каналу входного файла с паузами после каждой строки:
#!/bin/bash
while read l ; do
echo "$l"
sleep 1
done
Затем вызовите его как это:
(pause-input.sh | gnuplot ...) < somefile.dat
Я бы рекомендовал прочитать статью Википедии о хэш-таблицах - Я думаю, это поможет вам понять, что на самом деле означает {: ruby = > «red»}
.
Еще одно упражнение, которое может помочь вам понять ситуацию: рассмотрим {1 = > «красный»}
. Семантически это не означает «установить значение 1
на » красный «
», что невозможно в Руби. Скорее это означает "создать объект Hash и сохранить значение " red "
для ключа 1
.
Я не являюсь специалистом Oracle, но для получения метки времени, вероятно, необходим тип столбца DateTime
.
Для этого необходимо использовать java.sql.Timestamp
тип JDBC.
Хорошая попытка, но... При этом будет создано столько файлов, сколько строк в файле данных. Это выглядит уродливо для меня.
Мы можем написать сценарий shell/perl, чтобы создать сценарий gnuplot с такими командами, как
splot x1 y1 z1
pause 1
replot x2 y2 z2
pause 1
replot x3 y3 z3
pause 1
replot x4 y4 z4
, где xi, yi, zi = координаты в файле данных для i-го номера строки. пауза 1 приостановит ее на одну секунду.
Это всего лишь идея, хотя я не уверен, как выводить координаты непосредственно вместо подачи файла данных в gnuplot.
создайте файл графика, например. 'myplotfile.plt'. и поместите в него все команды, которые вы обычно вводите в gnuplot для построения графиков.
, затем просто добавьте строку
!sleep $Number_of_Seconds_to_Pause
в свой файл графика, где вы хотите, чтобы он был приостановлен, и запустите его из терминала с помощью
gnuplot myplotfile.plt
(расширение файла графика не имеет значения, если вы работаете в Windows или Mac, вы можете использовать .txt)
пример файла графика:
set title 'x squared'
plot x**2 title ''
!sleep 5
set title 'x cubed'
plot x**3 title ''
!sleep 5