Języki o typie statycznym zazwyczaj wymagają deklarowania typów zmiennych, które są następnie sprawdzane w czasie kompilacji w celu ograniczenia błędów. Słowo „statyczny” w „statycznie typowany” odnosi się do „statycznej analizy kodu”, która jest procesem sprawdzania kodu przed jego wykonaniem. Chociaż możliwe jest, aby język o typie statycznym mógł wywnioskować typ zmiennej z prawej strony wyrażenia lub rzeczywistych parametrów, w praktyce większość języków o typie statycznym wymaga jawnego zadeklarowania typów zmiennych.
Języki o typie dynamicznym generalnie nie wymagają deklaracji zmiennych, aby mieć typy, i wnioskują o typach zmiennych na podstawie typu obliczonego w wyniku oceny prawej strony każdej instrukcji przypisania lub rzeczywistych parametrów wywołania funkcji. Ponieważ zmienna może mieć wiele przypisań przez cały okres jej istnienia, jej typ może zmieniać się w czasie i dlatego nazywany jest „typowaniem dynamicznym”. Ponadto środowisko wykonawcze musi śledzić bieżący typ dla każdej zmiennej, więc typ jest powiązany z wartością, a nie z deklaracją zmiennej. Można to uznać za system informacji o środowisku wykonawczym (RTTI).
Elementy języków pisanych statycznie i dynamicznie można łączyć. Na przykład C # obsługuje zarówno zmienne o typie statycznym, jak i dynamicznym, a języki zorientowane obiektowo ogólnie obsługują hierarchię typów. Języki o typie statycznym zazwyczaj zapewniają różne sposoby na ominięcie sprawdzania typu, na przykład za pomocą rzutowania, odbicia i dynamicznego wywoływania.
Mocne vs. słabe pisanie odnosi się do kontinuum tego, jak bardzo język próbuje zapobiec błędom z powodu używania zmiennej tak, jakby był jednym typem, podczas gdy w rzeczywistości jest innym typem. Na przykład zarówno C, jak i Java są językami o typie statycznym, jednak Java korzysta ze znacznie silniejszego sprawdzania typów niż C. Poniższy kod C z przyjemnością się kompiluje i uruchamia, i wstawi losową wartość do zmiennej b w czasie wykonywania, najprawdopodobniej powodując pluskwa:
char *a = "123";
int b = (int)a;
Odpowiednik kodu Java spowoduje błąd kompilacji, co jest ogólnie preferowane:
String a = "123"
int b = (int)a;