Documentation Index Fetch the complete documentation index at: https://mintlify.com/meteor/meteor/llms.txt
Use this file to discover all available pages before exploring further.
The typescript package provides TypeScript support in Meteor applications, compiling .ts and .tsx files to JavaScript.
Installation
Overview
The typescript package provides:
TypeScript Compilation - Compile .ts and .tsx files
Type Checking - Static type checking during development
React Support - TSX for React components
Babel Integration - Combined with ECMAScript features
Source Maps - Debug original TypeScript source
Fast Refresh - Hot reloading for React components
Version : 5.9.3
Summary : Compiler plugin that compiles TypeScript and ECMAScript in .ts and .tsx files
Dependencies : babel-compiler, babel-runtime, modules, ecmascript-runtime, promise, dynamic-import
Dev Only : true (compilation happens at build time)
Getting Started
Basic TypeScript File
// server/main.ts
import { Meteor } from 'meteor/meteor' ;
import { Todos } from '../imports/collections/Todos' ;
Meteor . startup ( async () => {
const count : number = await Todos . find (). countAsync ();
console . log ( `Found ${ count } todos` );
});
Collection with Types
// imports/collections/Todos.ts
import { Mongo } from 'meteor/mongo' ;
interface Todo {
_id ?: string ;
text : string ;
done : boolean ;
userId : string ;
createdAt : Date ;
}
export const Todos = new Mongo . Collection < Todo >( 'todos' );
if ( Meteor . isServer ) {
Meteor . publish ( 'todos' , function () {
return Todos . find ({ userId: this . userId || '' });
});
}
Meteor . methods ({
async 'todos.insert' ( text : string ) : Promise < string > {
if ( ! this . userId ) {
throw new Meteor . Error ( 'not-authorized' );
}
return await Todos . insertAsync ({
text ,
done: false ,
userId: this . userId ,
createdAt: new Date ()
});
}
});
TypeScript Configuration
tsconfig.json
Create tsconfig.json in your project root:
{
"compilerOptions" : {
"target" : "ES2020" ,
"module" : "ESNext" ,
"lib" : [ "ES2020" , "DOM" ],
"moduleResolution" : "node" ,
"esModuleInterop" : true ,
"skipLibCheck" : true ,
"strict" : true ,
"noImplicitAny" : true ,
"strictNullChecks" : true ,
"strictFunctionTypes" : true ,
"strictPropertyInitialization" : true ,
"noImplicitThis" : true ,
"alwaysStrict" : true ,
"noUnusedLocals" : true ,
"noUnusedParameters" : true ,
"noImplicitReturns" : true ,
"allowSyntheticDefaultImports" : true ,
"resolveJsonModule" : true ,
"jsx" : "react" ,
"baseUrl" : "." ,
"paths" : {
"/imports/*" : [ "./imports/*" ]
}
},
"include" : [
"**/*.ts" ,
"**/*.tsx"
],
"exclude" : [
"node_modules" ,
".meteor"
]
}
Type Definitions
Install Meteor Types
npm install --save-dev @types/meteor
Using Meteor Types
import { Meteor } from 'meteor/meteor' ;
import { Mongo } from 'meteor/mongo' ;
import { check } from 'meteor/check' ;
// Types are automatically available
Meteor . startup (() => {
console . log ( 'Server started' );
});
// User type
const user : Meteor . User | null = Meteor . user ();
const userId : string | null = Meteor . userId ();
Custom Type Definitions
// types/index.d.ts
// Extend Meteor.User
declare module 'meteor/meteor' {
module Meteor {
interface User {
profile ?: {
name : string ;
avatar ?: string ;
};
roles ?: string [];
organizationId ?: string ;
}
}
}
// Extend settings
declare module 'meteor/meteor' {
module Meteor {
interface Settings {
public : {
apiUrl : string ;
features : {
newUI : boolean ;
};
};
private : {
apiKey : string ;
};
}
}
}
React with TypeScript
Functional Component
// imports/ui/TodoItem.tsx
import React from 'react' ;
interface TodoItemProps {
todo : {
_id : string ;
text : string ;
done : boolean ;
};
onToggle : ( id : string ) => void ;
onDelete : ( id : string ) => void ;
}
export const TodoItem : React . FC < TodoItemProps > = ({ todo , onToggle , onDelete }) => {
return (
< li >
< input
type = "checkbox"
checked = {todo. done }
onChange = {() => onToggle (todo._id)}
/>
< span style = {{ textDecoration : todo . done ? 'line-through' : 'none' }} >
{ todo . text }
</ span >
< button onClick = {() => onDelete (todo._id)} > Delete </ button >
</ li >
);
};
Component with State
import React , { useState , useEffect } from 'react' ;
import { useTracker } from 'meteor/react-meteor-data' ;
import { Todos } from '../collections/Todos' ;
interface TodoListProps {
filter ?: 'all' | 'active' | 'completed' ;
}
export const TodoList : React . FC < TodoListProps > = ({ filter = 'all' }) => {
const [ searchQuery , setSearchQuery ] = useState < string >( '' );
const { todos , loading } = useTracker (() => {
const handle = Meteor . subscribe ( 'todos' );
let selector : Mongo . Selector < Todo > = {};
if ( filter === 'active' ) {
selector . done = false ;
} else if ( filter === 'completed' ) {
selector . done = true ;
}
if ( searchQuery ) {
selector . text = { $regex: searchQuery , $options: 'i' };
}
return {
todos: Todos . find ( selector ). fetch (),
loading: ! handle . ready ()
};
}, [ filter , searchQuery ]);
if ( loading ) {
return < div > Loading ...</ div > ;
}
return (
< div >
< input
type = "text"
placeholder = "Search..."
value = { searchQuery }
onChange = {(e) => setSearchQuery (e.target.value)}
/>
< ul >
{ todos . map ( todo => (
< TodoItem key = {todo. _id } todo = { todo } />
))}
</ ul >
</ div >
);
};
Meteor Methods with Types
Define Method Types
// imports/api/methods/todos.ts
import { Meteor } from 'meteor/meteor' ;
import { check } from 'meteor/check' ;
import { Todos } from '../collections/Todos' ;
export interface TodoMethods {
'todos.insert' : ( text : string ) => Promise < string >;
'todos.update' : ( id : string , text : string ) => Promise < number >;
'todos.toggle' : ( id : string ) => Promise < number >;
'todos.remove' : ( id : string ) => Promise < number >;
}
Meteor . methods < TodoMethods >({
async 'todos.insert' ( text : string ) : Promise < string > {
check ( text , String );
if ( ! this . userId ) {
throw new Meteor . Error ( 'not-authorized' );
}
return await Todos . insertAsync ({
text ,
done: false ,
userId: this . userId ,
createdAt: new Date ()
});
},
async 'todos.toggle' ( id : string ) : Promise < number > {
check ( id , String );
const todo = await Todos . findOneAsync ( id );
if ( ! todo || todo . userId !== this . userId ) {
throw new Meteor . Error ( 'not-authorized' );
}
return await Todos . updateAsync ( id , {
$set: { done: ! todo . done }
});
}
});
Call Methods with Type Safety
// Client code
import { Meteor } from 'meteor/meteor' ;
import type { TodoMethods } from './methods/todos' ;
// Type-safe method calls
async function createTodo ( text : string ) : Promise < string > {
return await Meteor . callAsync < TodoMethods [ 'todos.insert' ]>( 'todos.insert' , text );
}
async function toggleTodo ( id : string ) : Promise < void > {
await Meteor . callAsync < TodoMethods [ 'todos.toggle' ]>( 'todos.toggle' , id );
}
Publications with Types
import { Meteor } from 'meteor/meteor' ;
import { Todos } from '../collections/Todos' ;
import { Posts } from '../collections/Posts' ;
// Simple publication
Meteor . publish ( 'todos' , function () {
if ( ! this . userId ) {
return this . ready ();
}
return Todos . find ({ userId: this . userId });
});
// Publication with parameters
Meteor . publish ( 'todosByStatus' , function ( status : 'active' | 'completed' ) {
check ( status , String );
return Todos . find ({
userId: this . userId || '' ,
done: status === 'completed'
});
});
// Multiple cursors
Meteor . publish ( 'userDashboard' , function () {
if ( ! this . userId ) {
return this . ready ();
}
return [
Todos . find ({ userId: this . userId }),
Posts . find ({ authorId: this . userId })
];
});
Generic Types
// Generic collection wrapper
class TypedCollection < T > extends Mongo . Collection < T > {
async findOneOrThrow ( selector : Mongo . Selector < T >) : Promise < T > {
const doc = await this . findOneAsync ( selector );
if ( ! doc ) {
throw new Meteor . Error ( 'not-found' , 'Document not found' );
}
return doc ;
}
async updateOne (
selector : Mongo . Selector < T >,
modifier : Mongo . Modifier < T >
) : Promise < void > {
const count = await this . updateAsync ( selector , modifier );
if ( count === 0 ) {
throw new Meteor . Error ( 'not-found' , 'No document updated' );
}
}
}
// Use generic collection
interface User {
_id ?: string ;
name : string ;
email : string ;
}
const Users = new TypedCollection < User >( 'users' );
Utility Types
// Omit _id for inserts
type TodoInsert = Omit < Todo , '_id' >;
const newTodo : TodoInsert = {
text: 'New todo' ,
done: false ,
userId: 'user123' ,
createdAt: new Date ()
};
// Partial for updates
type TodoUpdate = Partial < Todo >;
const update : TodoUpdate = {
done: true
};
// Pick specific fields
type TodoSummary = Pick < Todo , '_id' | 'text' | 'done' >;
const summary : TodoSummary = {
_id: '1' ,
text: 'Todo' ,
done: false
};
Async/Await with Types
// Async function with return type
async function getUserTodos ( userId : string ) : Promise < Todo []> {
return await Todos . find ({ userId }). fetchAsync ();
}
// Error handling with types
async function safeFetchTodo ( id : string ) : Promise < Todo | null > {
try {
const todo = await Todos . findOneAsync ({ _id: id });
return todo || null ;
} catch ( error ) {
console . error ( 'Error fetching todo:' , error );
return null ;
}
}
// Promise.all with types
async function loadAllData () : Promise <{
todos : Todo [];
users : Meteor . User [];
}> {
const [ todos , users ] = await Promise . all ([
Todos . find (). fetchAsync (),
Meteor . users . find (). fetchAsync ()
]);
return { todos , users };
}
Enums and Const Assertions
// Enum
enum TodoStatus {
Active = 'active' ,
Completed = 'completed' ,
Archived = 'archived'
}
interface TodoWithStatus {
_id : string ;
text : string ;
status : TodoStatus ;
}
// Const assertion
const PRIORITIES = [ 'low' , 'medium' , 'high' ] as const ;
type Priority = typeof PRIORITIES [ number ]; // 'low' | 'medium' | 'high'
interface TodoWithPriority {
_id : string ;
text : string ;
priority : Priority ;
}
Best Practices
Enable strict mode - Use "strict": true in tsconfig.json
Define interfaces for documents - Create types for all collection documents
Type method parameters and returns - Explicit types for all methods
Use generics - Make reusable typed utilities
// Good: Explicit types
interface Todo {
_id ?: string ;
text : string ;
done : boolean ;
}
const Todos = new Mongo . Collection < Todo >( 'todos' );
async function getTodo ( id : string ) : Promise < Todo | undefined > {
return await Todos . findOneAsync ({ _id: id });
}
// Avoid: Any types
const Todos = new Mongo . Collection ( 'todos' );
function getTodo ( id ) {
return Todos . findOne ({ _id: id });
}
Common Issues
Module Resolution
If imports aren’t working:
// tsconfig.json
{
"compilerOptions" : {
"moduleResolution" : "node" ,
"esModuleInterop" : true ,
"allowSyntheticDefaultImports" : true
}
}
Missing Types
# Install type definitions
npm install --save-dev @types/meteor
npm install --save-dev @types/react
npm install --save-dev @types/react-dom
ecmascript ES2015+ JavaScript support
babel-compiler Babel compilation engine
Source Code