Reputation: 59425
I am wondering if it is possible given a file with an exported type, could the types be extracted from the generic, to a computed type?
function example() {
return {
foo: 'hi',
bar: true,
baz: 1
};
}
export type Signature = ReturnType<typeof example>;
To this:
export type Signature = {
foo: string;
bar: boolean;
baz: number;
}
I don't believe that the tsc
cli does this, and I'm not sure what this process would be called.
Can tsc
create this export?
Are there any third-party tools that can do this?
The only way I know how to do this is hover over the variable in VSCode and copy the computed type, and that only works if it's short, and doesn't trail off ...
I found some other references to similar requests:
Upvotes: 10
Views: 1326
Reputation: 383
Looking into this question, without replicating VSCode's hover.ts
, I find that one, if not the only, answer to this question is:
tsserver
You need to communicate the line and char offset in your file to the server. One should be able to use abstract syntax tree (AST) in .ts
for that. I wrote a client in bash instead. Attached below, it supports calculating char offset from column (as seen in the VSCode statusbar). A log from a run of your source and a document position on the word "Signature" follows and the end comes very close to your wanted extraction.
$ (prepared=('open -s #.ts -i file' 'quickinfo -s #.ts -i file -n 9 -i line -n 20 -i _column_')&&. $(which tsssh))
ts < open -s #.ts -i file
{"seq": 1, "type": "request", "command": "open", "arguments": {"file": "#.ts"}}
ts < quickinfo -s #.ts -i file -n 9 -i line -n 20 -i _column_
{"seq": 1, "type": "request", "command": "quickinfo", "arguments": {"file": "#.ts", "line": 9, "offset": 19}}
event #0
event: typingsInstallerPid
body: {"pid": 65341}
response #0 (1)
command: quickinfo
body: {"kind": "type", "kindModifiers": "export", "start": {"line": 9, "offset": 13}, "end": {"line": 9, "offset": 22}, "displayString": "type Signature = {\n foo: string;\n bar: boolean;\n baz: number;\n}", "documentation": "", "tags": []}
displayString: type Signature = {
foo: string;
bar: boolean;
baz: number;
}
bash -O cmdhist -O lithist
with macports, and various other shopt..tsserver=./node_modules/typescript/bin/tsserver tsssh
..histfile= path/to/tsssh
. Multiple "prepared" can be specified as (prepared=("first" ... "last")&&. path/to/tsssh)
#!/usr/bin/env bash
( # Quick and dirty client for https://github.com/Microsoft/TypeScript/wiki/Standalone-Server-%28tsserver%29..
# Relies heavily on prerequisite http://kmkeen.com/jshon/, and compatible bash and gawk, while tput and tee could be cut out I guess..
# Developed on macOS 10.13.6 in version 5.0.16 `bash -O cmdhist -O lithist` with macports, and various other shopt..
# NB: You need to poll event/response manually by sending empty commandlines. Exit with kill -sigint , typically ctrl+C..
# Run in local repo like `tsserver=./node_modules/typescript/bin/tsserver tsssh`..
# Disable history with `histfile='' path/to/tsssh`. Multiple "prepared" can be specified as `(prepared=("first" ... "last")&&. path/to/tsssh)`
# Copyright 2020 Viktor Bergquist ([email protected]), license https://creativecommons.org/licenses/by-sa/4.0/
HISTFILE=${histfile-.tsssh_history} &&
{ ((\!-( x = xtrace )))||set -x ;} && ((!errexit))||set -e &&
state()(set +x;tput setaf $1;echo "${*:2}";tput sgr0;((\!-x))||set -x) >&2 && trap 'state 1 $?: "$BASH_COMMAND"' err &&
[[ ! $HISTFILE ]]||{ h=$HISTSIZE&&HISTSIZE=1&&set -o history&&HISTSIZE=$h&&history -s ''&&{ history -r "$HISTFILE"||:;};}&&
coproc ts (${tsserver:-tsserver}) &&set -o pipefail&&command sleep 1 &&
show(){ set +x; f=$1&&shift && i=$(cat) && declare -n n&&for n;do
n=$(((\!-x))||set -x; jshon <<<"$i" -e "${!n}" $f);((e=$?)) || echo "${!n}: $n"; done; ((\!-x))||set -x; return $e;} &&
extract(){ show "$@";} >/dev/null &&
compact()( "$@"|gawk -vORS= '{sub("^\\s+",!m[0]?"":" ")}1;{match($0,",$",m)}END{printf"\n"}') &&
function check(){ while {
read -rt.1 -d$'\r' h&&[[ $h =~ Content-Length:\ ([0-9]+) ]]&&read -r$t -N3&&read -r$t -N$((${BASH_REMATCH[1]}-1)) a;} <&${ts[0]};do
#set +x;echo 'ts > '"$a";((\!-x))||set -x
<<<"$a" extract -u type seq &&case $type in
( event)state 2 $type \#$seq
<<<"$a" show -u event ;;&
(response)<<<"$a" extract -u success request_seq&&case $success in
( false)state 1 $type \#$seq "($request_seq)"
<<<"$a" show -u command message ;;
( true)state 2 $type \#$seq "($request_seq)"
<<<"$a" show -u command message metadata 2>/dev/null ;;
( *)state 1 "unknown success: $success" ;esac ;&
( event)<<<"$a" compact show '' body ;! [[ $type = response && $success = true ]]||case $command in
( *)<<<"$a" extract '' body ;;&
( quickinfo) <<< "$body" show -u displayString ;esac ;;
( *)state 1 "unknown type: $type" ;esac ;done;} &&
seq=0 && for p in ${!prepared[@]} -1;do for fd in <(echo "${prepared[p]}") 0;do fd="${fd##*/}"; (((p<0)!=(0<fd)))||continue
while check <&-; set +x; read -p 'ts < ' -era Q; do
((\!${#Q[*]}))&&{ tput -S<<<$'cuu1\nel'
((\!-x))||set -x;} ||
{ ((\!-x))||set -x
history -s "${Q[*]}"&&{ [[ ! $HISTFILE ]]||{ [[ ! -a $HISTFILE ]]&&history -w "$HISTFILE"||history -a "$HISTFILE";};} &&
d=$(compact jshon <<<{} -n$((++seq)) -i seq -s request -i type -s "$Q" -i command -n {} "${Q[@]:1}" -i arguments)
A=$(compact jshon <<<{} "${Q[@]:1}")
! <<<"$A" extract -u file line _column_ 2>/dev/null ||
{ o=$(gawk -vT="${tabs:-4}" -vC="$_column_" FNR=="$line"'{
t=-1;for(o=0;o<=length();o++){t++;if("\t"==substr($0,o,1)){t+=T-1;t-=t%T}if(t>=C)break}print o-1
}' "$file") &&
d=$(<<<"$d" compact jshon -e arguments -d _column_ -n "$o" -i offset -p);}
tee <<<"$d" /dev/stderr >&${ts[1]};}
done<&$fd;done;done;set +x;echo bye) #ts < eg: reload -s index.ts -i file ^M quickinfo -s index.ts -i file -n 4 -i line -n 7 -i _column_
With all your question's good references, you surely know some "trail off" that you mention can be prevented with "compilerOptions":{"noErrorTruncation":true}
in the tsconfig.json
:)
To the end of those references I can add that there's also an Interactive Diagnostics PR 31384 (draft) to hope for :)
For the time being I'll look into the interesting utility type in the related Q&A How can I see the full expanded contract of a Typescript type?
Upvotes: 6